How to combine all sublist elements into one list - r

I have a list (of length 3) which is made up of sublists (each of differing length - 2, 2, 3). I would like to store all of this as one big list (e.g., no sublists - just one list of length 7). I understand how to do it manually, but is there a function or command I can use?
I would like to be able to do this for lists and sublists of any length.
Here's an example of the list:
[[1]]
[[1]][[1]]
name n l_1 t t_3 t_4 t_5 cluster
12 563035 19 9.263158 0.2017045 0.06379453 0.075876830 0.095852895 1
14 563037 19 8.026316 0.2076503 0.05634675 0.098684211 -0.104566563 1
[[1]][[2]]
name n l_1 t t_3 t_4 t_5 cluster
13 563036 20 7.200000 0.1838450 -0.06428098 0.085681987 -0.011070830 2
17 563042 20 7.725000 0.2168285 0.15161037 0.117570045 -0.067102568 2
[[2]]
[[2]][[1]]
name n l_1 t t_3 t_4 t_5 cluster
1 561101 11 6.772727 0.19731544 0.029478458 -0.128117914 6.235828e-02 1
44 563080 11 7.545455 0.18554217 0.103896104 0.285714286 -2.164502e-02 1
[[2]][[2]]
name n l_1 t t_3 t_4 t_5 cluster
48 566017 33 10.400000 0.2037624 0.16432326 0.1166006937 -0.012830017 2
49 566018 22 9.218182 0.2113271 0.30646667 0.2502280702 0.189838207 2
50 566020 19 11.736842 0.3111609 0.51217445 0.5147883012 0.462723120 2
[[3]]
[[3]][[1]]
name n l_1 t t_3 t_4 t_5 cluster
158 568004 18 8.722222 0.1787186 -0.05083857 0.06498952 0.06918239 1
161 568046 19 11.794737 0.3646190 0.54582540 0.49747236 0.32255755 1
162 568047 18 12.916667 0.3366224 0.53523112 0.40464111 0.29960541 1
163 568048 20 11.590000 0.3918986 0.50007725 0.43039556 0.34299752 1
[[3]][[2]]
name n l_1 t t_3 t_4 t_5 cluster
165 568050 20 9.125000 0.2034607 0.29789747 0.31073776 0.09157738 2
167 568054 20 8.850000 0.1332144 0.09895833 0.18636204 0.04641544 2
[[3]][[3]]
name n l_1 t t_3 t_4 t_5 cluster
168 568058 20 8.675000 0.2012741 0.18161266 0.200319163 -0.009375416 3
170 568061 18 24.861111 0.7394676 0.91836281 0.928317483 0.905563950 3
Many thanks,
Sylvia

For your specific question, the answer is simple:
unlist(mylist, recursive = FALSE)
However, you asked how to be able to do this for a list with an arbitrary number of sublists. That is a bit more tricky. Fortunately, an Akhil S Bhel has tackled that problem for us and created a function called LinearizeNestedList. His site is down at the moment, but I had put his function up as a Github Gist.
First, we'll create some sample data with nested lists within nested lists.
NList <- list(a = "a", # Atom
b = 1:5, # Vector
c = data.frame(x = runif(5), y = runif(5)),
d = matrix(runif(4), nrow = 2),
e = list(l = list("a", "b"),
m = list(1:5, 5:10),
n = list(list(1), list(2))))
The source list looks like this. Notice the nesting that happens with the nested list item "e".
NList
# $a
# [1] "a"
#
# $b
# [1] 1 2 3 4 5
#
# $c
# x y
# 1 0.7893562 0.47761962
# 2 0.0233312 0.86120948
# 3 0.4772301 0.43809711
# 4 0.7323137 0.24479728
# 5 0.6927316 0.07067905
#
# $d
# [,1] [,2]
# [1,] 0.09946616 0.5186343
# [2,] 0.31627171 0.6620051
#
# $e
# $e$l
# $e$l[[1]]
# [1] "a"
#
# $e$l[[2]]
# [1] "b"
#
#
# $e$m
# $e$m[[1]]
# [1] 1 2 3 4 5
#
# $e$m[[2]]
# [1] 5 6 7 8 9 10
#
#
# $e$n
# $e$n[[1]]
# $e$n[[1]][[1]]
# [1] 1
#
#
# $e$n[[2]]
# $e$n[[2]][[1]]
# [1] 2
You can see how LinearizeNestedList "flattens" all sublists so you end up with a single list.
LinearizeNestedList(NList)
# $a
# [1] "a"
#
# $b
# [1] 1 2 3 4 5
#
# $c
# x y
# 1 0.7893562 0.47761962
# 2 0.0233312 0.86120948
# 3 0.4772301 0.43809711
# 4 0.7323137 0.24479728
# 5 0.6927316 0.07067905
#
# $d
# [,1] [,2]
# [1,] 0.09946616 0.5186343
# [2,] 0.31627171 0.6620051
#
# $`e/l/1`
# [1] "a"
#
# $`e/l/2`
# [1] "b"
#
# $`e/m/1`
# [1] 1 2 3 4 5
#
# $`e/m/2`
# [1] 5 6 7 8 9 10
#
# $`e/n/1/1`
# [1] 1
#
# $`e/n/2/1`
# [1] 2
By the way, I forgot to mention that you can flatten data.frames in lists too (since a data.frame is a special type of list in R.
If you really want to flatten everything out (well, except arrays, since they are just vectors with dims), add LinearizeDataFrames = TRUE to your LinearizeNestedList call:
LinearizeNestedList(NList, LinearizeDataFrames=TRUE)

how about this:
dissolve <- function(x){
operator <- function(x){
if(is.list(x)){
for(i in seq(x)){
operator(x[[i]])
}
}else{
combi[[length(combi)+1]] <<- x
}
}
combi=list()
operator(x)
return(combi)
}

.... does unlist(mylist) work?

Related

How to group list elements according to groups defined in a grouping vector?

Consider a list and a grouping vector
l = list(3:4, 8:10, 7:8)
# [[1]]
# [1] 3 4
#
# [[2]]
# [1] 8 9 10
#
# [[3]]
# [1] 7 8
g = c("A", "B", "A")
What is the easiest way to group l elements according to groups defined in g, such that we get:
l_expected = list(c(3:4, 7:8), 8:10))
# [[1]]
# [1] 3 4 7 8
#
# [[2]]
# [1] 8 9 10
One way is to use tapply + unlist, and unname if necessary.
tapply(l, g, unlist)
output
$A
[1] 3 4 7 8
$B
[1] 8 9 10
Using split
lapply(split(l, g), unlist)
$A
[1] 3 4 7 8
$B
[1] 8 9 10
Or get the lengths and split after unlisting
split(unlist(l), rep(g, lengths(l)))
$A
[1] 3 4 7 8
$B
[1] 8 9 10

Use mapply or lapply to nested list

I want to apply a sample function to a nested list (I will call this list bb) and I also have a list of numbers (I will call this list k) to be supplied in the sample function. I would like each of the numbers in k to iterate through all the values of each list in bb. How to do this using mapply or lapply?
Here are the data:
k <- list(1,2,4,3) #this is the list of numbers to be supplied in the `sample.int` function
b1 <- list(c(1,2,3),c(2,3,4),c(3,4,5),c(4,5,6)) #The first list of bb
b2 <- list(c(1,2),c(2,3),c(3,4),c(4,5), c(5,6)) #The second list of bb
bb <- list(b1,b2) #This is list bb containing b1 and b2 whose values are to be iterated through
I created this mapply function but it didn't get the expected outcome:
mapply(function(x, y) {
x[sample.int(y,y, replace = TRUE)]
}, bb,k, SIMPLIFY = FALSE)
This only returns 10 output values but I would like each number of k to loop through all values of the two lists in bb and so there should be 10*2 outputs for the two lists in bb. I might be using mapply in the wrong way and so I would appreciate if anyone can point me to the right direction!
outer is your friend. It's normally used to calculate the outer matrix product. Consider:
outer(1:3, 2:4)
1:3 %o% 2:4 ## or
# [,1] [,2] [,3]
# [1,] 2 3 4
# [2,] 4 6 8
# [3,] 6 9 12
It also has a FUN= argument that defaults to "*". However it enables you to calculate any function over the combinations of x and y cross-wise, i.e. x[1] X y[1], x[1] X y[2], ... whereas *apply functions only calculate x[1] X y[1], x[2] X y[2], .... So let's do it:
FUN <- Vectorize(function(x, y) x[sample.int(y, y)])
set.seed(42)
res <- outer(bb, k, FUN)
res
# [,1] [,2] [,3] [,4]
# [1,] List,1 List,2 List,4 List,3
# [2,] List,1 List,2 List,4 List,3
This result looks a little weird, but we may easily unlist it.
res <- unlist(res, recursive=F)
Result
res
# [[1]]
# [1] 1 2 3
#
# [[2]]
# [1] 1 2
#
# [[3]]
# [1] 1 2 3
#
# [[4]]
# [1] 2 3 4
#
# [[5]]
# [1] 2 3
#
# [[6]]
# [1] 1 2
#
# [[7]]
# [1] 2 3 4
#
# [[8]]
# [1] 4 5 6
#
# [[9]]
# [1] 1 2 3
#
# [[10]]
# [1] 3 4 5
#
# [[11]]
# [1] 3 4
#
# [[12]]
# [1] 4 5
#
# [[13]]
# [1] 2 3
#
# [[14]]
# [1] 1 2
#
# [[15]]
# [1] 1 2 3
#
# [[16]]
# [1] 2 3 4
#
# [[17]]
# [1] 3 4 5
#
# [[18]]
# [1] 2 3
#
# [[19]]
# [1] 3 4
#
# [[20]]
# [1] 1 2
VoilĂ , 20 results.

split list into lists each of length x

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)

Getting all the combination of numbers from a list that would sum to a specific number

I have the following list of numbers (1,3,4,5,7,9,10,12,15) and I want to find out all the possible combinations of 3 numbers from this list that would sum to 20.
My research on stackoverflow has led me to this post:
Finding all possible combinations of numbers to reach a given sum
There is a solution provided by Mark which stand as follows:
subset_sum = function(numbers,target,partial=0){
if(any(is.na(partial))) return()
s = sum(partial)
if(s == target) print(sprintf("sum(%s)=%s",paste(partial[-1],collapse="+"),target))
if(s > target) return()
for( i in seq_along(numbers)){
n = numbers[i]
remaining = numbers[(i+1):length(numbers)]
subset_sum(remaining,target,c(partial,n))
}
}
However I am having a hard time trying to tweak this set of codes to match my problem. Or may be there is a simpler solution?
I want the output in R to show me the list of numbers.
Any help would be appreciated.
You can use combn function and filter to meet your criteria. I have performed below calculation in 2 steps but one can perform it in single step too.
v <- c(1,3,4,5,7,9,10,12,15)
AllComb <- combn(v, 3) #generates all combination taking 3 at a time.
PossibleComb <- AllComb[,colSums(AllComb) == 20] #filter those with sum == 20
#Result: 6 sets of 3 numbers (column-wise)
PossibleComb
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 1 1 1 3 3 4
# [2,] 4 7 9 5 7 7
# [3,] 15 12 10 12 10 9
#
# Result in list
split(PossibleComb, col(PossibleComb))
# $`1`
# [1] 1 4 15
#
# $`2`
# [1] 1 7 12
#
# $`3`
# [1] 1 9 10
#
# $`4`
# [1] 3 5 12
#
# $`5`
# [1] 3 7 10
#
# $`6`
# [1] 4 7 9
The combn also have a FUN parameter which we can describe to output as list and then Filter the list elements based on the condition
Filter(function(x) sum(x) == 20, combn(v, 3, FUN = list))
#[[1]]
#[1] 1 4 15
#[[2]]
#[1] 1 7 12
#[[3]]
#[1] 1 9 10
#[[4]]
#[1] 3 5 12
#[[5]]
#[1] 3 7 10
#[[6]]
#[1] 4 7 9
data
v <- c(1,3,4,5,7,9,10,12,15)

Splitting numeric vectors in R

If I have a vector, c(1,2,3,5,7,9,10,12)...and another vector c(3,7,10), how would I produce the following:
[[1]]
1,2,3
[[2]]
5,7
[[3]]
9,10
[[4]]
12
Notice how 3 7 and 10 become the last number of each list element (except the last one). Or in a sense the "breakpoint". I am sure there is a simple R function I am unknowledgeable of or having loss of memory.
Here's one way using cut and split:
split(x, cut(x, c(-Inf, y, Inf)))
#$`(-Inf,3]`
#[1] 1 2 3
#
#$`(3,7]`
#[1] 5 7
#
#$`(7,10]`
#[1] 9 10
#
#$`(10, Inf]`
#[1] 12
Could do
split(x, cut(x, unique(c(y, range(x)))))
## $`[1,3]`
## [1] 1 2 3
## $`(3,7]`
## [1] 5 7
## $`(7,10]`
## [1] 9 10
## $`(10,12]`
## [1] 12
Similar to #beginneR 's answer, but using findInterval instead of cut
split(x, findInterval(x, y + 1))
# $`0`
# [1] 1 2 3
#
# $`1`
# [1] 5 7
#
# $`2`
# [1] 9 10
#
# $`3`
# [1] 12

Resources