I would like to add list elements iteratively in R, so that later elements can use the elements created earlier. The desired behavior is as follows:
lst <- list(a = 1,
b = 2,
c = b)
lst
## $a
## [1] 1
##
## $b
## [1] 2
##
## $c
## [1] 2
I know that I can easily accomplish the same using e.g.
lst <- list(a = 1,
b = 2)
lst[['c']] <- lst[['b']]
But I was wondering, if I could do this in one step.
Here's another way
rev(within(list(), { a = 1; b = 2; c = b }))
# $a
# [1] 1
#
# $b
# [1] 2
#
# $c
# [1] 2
Update: This is now possible with the lst function of the tibble package:
tibble::lst(a = 1, b = 2, c = b)
## $a
## [1] 1
##
## $b
## [1] 2
##
## $c
## [1] 2
My previous workaround was using mutate from plyr:
mylist <- function(...) plyr::mutate(.data=list(), ...)
mylist(a = 1,
b = 2,
c = b)
## $a
## [1] 1
##
## $b
## [1] 2
##
## $c
## [1] 2
A more classic idea:
mylist = function(...)
{
args = as.list(substitute(list(...)))[-1]
lapply(args, eval, envir = args)
}
mylist(a = 1, b = 2, c = a + b)
#$a
#[1] 1
#
#$b
#[1] 2
#
#$c
#[1] 3
For a strict iterative approach, a loop is needed:
mylist = function(...)
{
args = as.list(substitute(list(...)))[-1]
for(i in seq_along(args)) args[[i]] = eval(args[[i]], envir = args)
return(args)
}
mylist(a = 1, b = a + 1, c = b + 1)
#$a
#[1] 1
#
#$b
#[1] 2
#
#$c
#[1] 3
Related
Ideally I would like to make use of purrr's accumulate function or similar.
Let's say I want to make use of utils::combn function iteratively, and get all the intermediate results (ideally put inside a list of lists).
In example below, initially, parameter x = 4, thus m will be also 4 (but (x, m) could be (5, 5), (6, 6), ...). Then, after first loop, x will be previous result, whilst m goes down by one, iteratively until m = 2.
n1 <- combn(x = 4, m = 4, simplify = FALSE)
n2 <- map(n1, ~ combn(.x, 3, simplify = FALSE))
n3 <- map(n2, ~ map(., ~ combn(.x, 2, simplify = FALSE)))
> n1
[[1]]
[1] 1 2 3 4
> n2
[[1]]
[[1]][[1]]
[1] 1 2 3
[[1]][[2]]
[1] 1 2 4
[[1]][[3]]
[1] 1 3 4
[[1]][[4]]
[1] 2 3 4
> n3
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
[1] 1 2
[[1]][[1]][[2]]
[1] 1 3
[[1]][[1]][[3]]
[1] 2 3
[[1]][[2]]
[[1]][[2]][[1]]
[1] 1 2
[[1]][[2]][[2]]
[1] 1 4
[[1]][[2]][[3]]
[1] 2 4
[[1]][[3]]
[[1]][[3]][[1]]
[1] 1 3
[[1]][[3]][[2]]
[1] 1 4
[[1]][[3]][[3]]
[1] 3 4
[[1]][[4]]
[[1]][[4]][[1]]
[1] 2 3
[[1]][[4]][[2]]
[1] 2 4
[[1]][[4]][[3]]
[1] 3 4
As you can imagine, I want to get all possible combinations, e.g.:
choose(4, 4) -> choose(result, 3) -> choose(result, 2).
Any help or ideas would be much appreciated.
You can use accumulate + map_depth:
combn_recur <- function(n) {
accumulate(c(n, 0:(n-2)),
~ map_depth(.x, .y, combn, m = n-.y, simplify = FALSE))[-1]
}
all.equal(combn_recur(4), c(n1, n2, n3))
# TRUE
combn_recur(3)
# [[1]]
# [1] 1 2 3
#
# [[2]]
# [[2]][[1]]
# [1] 1 2
#
# [[2]][[2]]
# [1] 1 3
#
# [[2]][[3]]
# [1] 2 3
combn_recur(2)
# [[1]]
# [1] 1 2
combn_recur(1)
# Error in .f(.x[[i]], ...) : n < m
I would like to flatten this list of arguments
args <- list(
a = 1,
b = "2",
list = list(c = 3, d = list(d1 = 5, d2 = 6)),
e = data.frame(e1 = c("a", "b"), e2 = c(7, 8))
)
on this
args <- list(
a = 1,
b = "2",
c = 3,
d = list(d1 = 5, d2 = 6),
e = data.frame(e1 = c("a", "b"), e2 = c(7, 8))
)
Because I need get work this function call
g <- function(x, y, ...){
do.call(f, x, y, ...)
}
g(x = x1, y = y1, args)
That does not work:
reduce(
.x = args,
.f = function(x) {
ifelse(
is.list(x),
lapply(x, `[[`),
x
)
}
)
that throws
Error in fn(out, elt, ...) : unused argument (elt)
Update: to OPs new data:
purrr::c(flatten(args[1:3]), args[4])
$a
[1] 1
$b
[1] "2"
$c
[1] 3
$d
$d$d1
[1] 5
$d$d2
[1] 6
$e
e1 e2
1 a 7
2 b 8
As you already state in your question "I would like to flatten this list of arguments" -> We could use purrrs flatten() function:
library(purrr)
flatten(args)
$a
[1] 1
$b
[1] "2"
$c
[1] 3
$d
$d$d1
[1] 5
$d$d2
[1] 6
$e
[1] 5
You can try the code below using for loops
res <- c()
for (v in args) {
if (is.list(v) & !is.data.frame(v)) {
res <- c(res,v)
} else {
res <- c(res, list(v))
}
}
or via Reduce
res <- Reduce(
function(x,y) {
c(x, ifelse(is.list(y) & !is.data.frame(y), I, list)(y))
},
args,
c()
)
and you will obtain
> res
[[1]]
[1] 1
[[2]]
[1] "2"
$c
[1] 3
$d
$d$d1
[1] 5
$d$d2
[1] 6
[[5]]
e1 e2
1 a 7
2 b 8
The output of map always be the same dim. So you need a for loop.
output <- NULL
for (x in seq(length(args))) {
list <- args[x]
if (is.list(args[[x]]) && !is.data.frame(args[[x]])) {
list <- flatten(args[x])
}
output <- append(output, list)
}
output
$a
[1] 1
$b
[1] "2"
$c
[1] 3
$d
$d$d1
[1] 5
$d$d2
[1] 6
$e
e1 e2
1 a 7
2 b 8
Given I have the vector and a target number
target.mountain <- 10
Roll_dice <- sample(1:6, 4, replace=TRUE)
With Roll_dice producing
[1] 6, 5, 3, 2 as an example
How can I produce a list of all numbers in Roll_dice with all the ways of adding them together by combining either 2, 3 or 4 of the values in Roll_dice together in a list
For example [1] 2, 3, 5, 5, 6, 7, 11, ....
I would like you to check out the RccpAlgos-package, which has some awesome (and fast!) functions for fast operations on combinations/permutations with constraints.
update
library(RcppAlgos)
library(vecsets)
library(data.table)
target.mountain <- 10
Roll_dice <- c(5, 5, 3, 2)
L <- lapply( 2:4, function(x) {
as.data.table(comboGeneral( Roll_dice,
x,
constraintFun = "sum",
comparisonFun = "==",
limitConstraints = target.mountain ),
keep.rownames = TRUE )
})
# [[1]]
# V1 V2
# 1: 5 5
#
# [[2]]
# V1 V2 V3
# 1: 2 3 5
#so 5-5 of 2-3-5 can be chosen to get to 10
#remaining dice
DT <- data.table::rbindlist( L, fill = TRUE )
remains <- lapply( transpose(DT), function(x) {
v <- as.vector(x)
v <- v[ !is.na(v) ]
sum( vecsets::vsetdiff( Roll_dice, v) )
})
remains
#witrh leftovers:
# $V1
# [1] 5
#
# $V2
# [1] 5
old answer
library(RcppAlgos)
target.mountain <- 10
Roll_dice <- c(6, 4, 5, 5)
sapply( 2:4, function(x) {
comboGeneral( Roll_dice,
x,
constraintFun = "sum",
comparisonFun = "==",
limitConstraints = target.mountain )
})
# [[1]]
# [,1] [,2]
# [1,] 4 6
# [2,] 5 5
#
# [[2]]
# [,1] [,2] [,3]
#
# [[3]]
# [,1] [,2] [,3] [,4]
Something like this?
> sapply(
+ 2:4,
+ function(k) combn(Roll_dice, k, sum)
+ )
[[1]]
[1] 11 9 8 8 7 5
[[2]]
[1] 14 13 11 10
[[3]]
[1] 16
Or do you need this?
> lapply(
+ setNames(2:4, 2:4),
+ function(k) target.mountain %in% combn(Roll_dice, k, sum)
+ )
$`2`
[1] FALSE
$`3`
[1] TRUE
$`4`
[1] FALSE
I am a beginner in R. I have a vast data set and I am trying to create a loop to optimize the time.
I have something like:
a <- c ('exam12', 'example22', 'e33')
b <- list (c (2,4,5,6), c (10,4,8,6), c (25, 3, 7, 30))
And I would like to use the strings of a as the name of objects for other values, obtaining, in my environment, something like:
exam <- c (2,4,5,6)
example <- c (10,4,8,6)
e <- c (25, 3, 7, 30)
I tried the following:
for (i in seq_along (a)) {
for (j in seq_along (b)) {
str_sub (a [i], start = 1, end = -1) <- b [j]
}
}
But I was not successful. I appreciate any help.
You can use list2env:
a <- c ('exam12', 'example22', 'e33')
b <- list (c (2,4,5,6), c (10,4,8,6), c (25, 3, 7, 30))
a
# [1] "exam12" "example22" "e33"
b
# [[1]]
# [1] 2 4 5 6
#
# [[2]]
# [1] 10 4 8 6
#
# [[3]]
# [1] 25 3 7 30
ls()
# [1] "a" "b"
list2env(setNames(b, sub("\\d+$", "", a)), .GlobalEnv)
# <environment: R_GlobalEnv>
ls()
# [1] "a" "b" "e" "exam" "example"
exam
# [1] 2 4 5 6
For reference, you could also do this with assign, for example:
for (i in seq_along(a)) {
assign(sub("\\d+$", "", a[i]), b[[i]])
}
Simple problem, given a list:
main_list <- list(1:3,
4:6,
7:9,
10:12,
13:15)
main_list
# [[1]]
# [1] 1 2 3
# [[2]]
# [1] 4 5 6
# [[3]]
# [1] 7 8 9
# [[4]]
# [1] 10 11 12
# [[5]]
# [1] 13 14 15
I want to split the list into multiple lists where I break up the original one into lists each of length x. So if I said x = 2, I would get 3 lists of length 2, 2 and the leftover 1:
target <- list(list(1:3,
4:6),
list(7:9,
10:12),
list(13:15))
target
# [[1]]
# [[1]][[1]]
# [1] 1 2 3
# [[1]][[2]]
# [1] 4 5 6
# [[2]]
# [[2]][[1]]
# [1] 7 8 9
# [[2]][[2]]
# [1] 10 11 12
# [[3]]
# [[3]][[1]]
# [1] 13 14 15
Something like:
my_split <- function(listtest, x) {
split(listtest, c(1:x))
}
target <- my_split(main_list, 2)
Thanks
here is an option with gl
split(main_list, as.integer(gl(length(main_list), 2, length(main_list))))
It can be converted to a custom function
f1 <- function(lstA, n) {
l1 < length(lstA)
split(lstA, as.integer(gl(l1, n, l1)))
}
EDIT: no conditional logic needed. Just use split() with c() and rep():
my_split <- function(l, x){
l_length <- length(l)
l_div <- l_length / x
split(l, c(rep(seq_len(l_div), each = x), rep(ceiling(l_div), l_length %% x)))
}
my_split(main_list, 2)