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
Related
Consider a vector:
vec <- c(1, 3, 4, 3, 3, 1, 1)
I'd like to get, for each element of the vector, a subset of the values in between the nth element and its previous occurrence.
The expected output is:
f(vec)
# [[1]]
# [1] 1
#
# [[2]]
# [1] 3
#
# [[3]]
# [1] 4
#
# [[4]]
# [1] 3 4 3
#
# [[5]]
# [1] 3 3
#
# [[6]]
# [1] 1 3 4 3 3 1
#
# [[7]]
# [1] 1 1
We may loop over the sequence of the vector, get the index of the last match of the same element ('i1') from the previous elements of the vector and get the sequence (:) to subset the vector
lapply(seq_along(vec), function(i) {
i1 <- tail(which(vec[1:(i-1)] == vec[i]), 1)[1]
i1[is.na(i1)] <- i
vec[i1:i]
})
-output
[[1]]
[1] 1
[[2]]
[1] 3
[[3]]
[1] 4
[[4]]
[1] 3 4 3
[[5]]
[1] 3 3
[[6]]
[1] 1 3 4 3 3 1
[[7]]
[1] 1 1
I want to add some vectors to a list, and I want to that show like this:
1.1
2.1 2
3.1 2 10
4.1 10
5.2
6.2 10
7.10
this is my code:
subsets <- function(s) {
res <- list()
n <- length(s)
s <- sort(s)
help <- function(temp, index, res) {
tmp <- temp
res <- append(res, tmp)
i <- index
while (i < n + 1 ) {
temp <- append(temp, s[i])
res <- help(temp, i + 1, res)
temp <- temp[-length(temp)]
i <- i + 1
}
return(res)
}
res <- help(c(), 1, res)
return(res)
}
s <- c(1, 10, 2)
subsets(s)
the output is:
1.1
2.1
3.2
4.1
5.2
6.10
7.1
8.10
9.2
10.2
11.10
12.10
Could somebody do me a favor? I am a new man for R, and I don't know what should I do...
You may use combn(). Loop over number of elements 0:3 sublist should contain (or 1:3 if empty element not wanted). Except the order this is equivalent to Python [[], [1], [1, 2], [1, 2, 10], [1, 10], [2], [2, 10], [10]].
lapply(0:3, \(m) combn(c(1, 2, 10), m, simplify=FALSE)) |>
unlist(recursive=FALSE)
# [[1]]
# numeric(0)
#
# [[2]]
# [1] 1
#
# [[3]]
# [1] 2
#
# [[4]]
# [1] 10
#
# [[5]]
# [1] 1 2
#
# [[6]]
# [1] 1 10
#
# [[7]]
# [1] 2 10
#
# [[8]]
# [1] 1 2 10
Note: R >= 4.1 used.
If you want your vectors to be in a list, you can use unlist:
unlist(list)
# [1] 1 1 2 1 2 10 1 10 2 2 10 10
Or add as.list if you want everything in a list of one item:
as.list(unlist(list))
[[1]]
[1] 1
[[2]]
[1] 1
[[3]]
[1] 2
[[4]]
[1] 1
[[5]]
[1] 2
[[6]]
[1] 10
[[7]]
[1] 1
[[8]]
[1] 10
[[9]]
[1] 2
[[10]]
[1] 2
[[11]]
[1] 10
[[12]]
[1] 10
Say I have a list of vectors like this:
list.of.vec <- data.frame(id = c(1,2,3,4)) %>%
mutate(a = list(list(c(1,2,3), c(2,3,4)), list(c(2,4,5), c(1,3,4)), list(c(1,2,3), c(4,3,4)), list(c(3,2,3), c(2,3,4))))
how can I arrange a such that in each pair of vectors, the one with the bigger first values goes first? E.g., if there was a list c(1,2,3), c(2,3,4), it should become c(2,3,4), c(1,2,3). And if first values are equal then it looks at the next value.
We can use rrapply
library(rrapply)
library(purrr)
library(dplyr)
list.of.vec <- list.of.vec %>%
mutate(a = map(a, ~ .x[order(-rrapply(.x, f = function(x) x[1],
how = 'unlist'))]))
-output
> list.of.vec
id a
1 1 2, 3, 4, 1, 2, 3
2 2 2, 4, 5, 1, 3, 4
3 3 4, 3, 4, 1, 2, 3
4 4 3, 2, 3, 2, 3, 4
> list.of.vec$a
[[1]]
[[1]][[1]]
[1] 2 3 4
[[1]][[2]]
[1] 1 2 3
[[2]]
[[2]][[1]]
[1] 2 4 5
[[2]][[2]]
[1] 1 3 4
[[3]]
[[3]][[1]]
[1] 4 3 4
[[3]][[2]]
[1] 1 2 3
[[4]]
[[4]][[1]]
[1] 3 2 3
[[4]][[2]]
[1] 2 3 4
You can use -
list.of.vec$a <- lapply(list.of.vec$a, function(x) {
inds <- match(TRUE, x[[1]] != x[[2]])
if(x[[1]][inds] > x[[2]][inds]) x else rev(x)
})
list.of.vec$a
#[[1]]
#[[1]][[1]]
#[1] 2 3 4
#[[1]][[2]]
#[1] 1 2 3
#[[2]]
#[[2]][[1]]
#[1] 2 4 5
#[[2]][[2]]
#[1] 1 3 4
#[[3]]
#[[3]][[1]]
#[1] 4 3 4
#[[3]][[2]]
#[1] 1 2 3
#[[4]]
#[[4]][[1]]
#[1] 3 2 3
#[[4]][[2]]
#[1] 2 3 4
inds would return the index for each list that we need to compare, an index where the value is different in both the vectors. If the first index has a higher value we return the list as it is without any change or else we return the reversed list.
We can try
lapply(
a,
function(x) {
x[order(-sapply(x, `[`, 1))]
}
)
which gives
[[1]]
[[1]][[1]]
[1] 2 3 4
[[1]][[2]]
[1] 1 2 3
[[2]]
[[2]][[1]]
[1] 2 4 5
[[2]][[2]]
[1] 1 3 4
[[3]]
[[3]][[1]]
[1] 4 3 4
[[3]][[2]]
[1] 1 2 3
[[4]]
[[4]][[1]]
[1] 3 2 3
[[4]][[2]]
[1] 2 3 4
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)
I am trying to combine two lists that complement each other, where one contains half the set of values and the second the other half:
v1 <- c(1,2,2,4)
v2 <- c(NULL)
v3 <- c(1,2,2,4)
l1 <- list(v1,v2,v3)
v1b <- c(NULL)
v2b <- c(1,2,2,4)
v3b <- c(NULL)
l2 <- list(v1b,v2b,v3b)
> l1
[[1]]
[1] 1 2 2 4
[[2]]
NULL
[[3]]
[1] 1 2 2 4
> l2
[[1]]
NULL
[[2]]
[1] 1 2 2 4
[[3]]
NULL
The desired result is:
[[1]]
[1] 1 2 2 4
[[2]]
[1] 1 2 2 4
[[3]]
[1] 1 2 2 4
I tried several ways. This is the closest I got:
> sapply(l1, function(x) ifelse(x == "NULL", l2[[x]], x))
[[1]]
[1] 1 2 2 4
[[2]]
logical(0)
[[3]]
[1] 1 2 2 4
Any help is appreciated.