This question already has answers here:
How to flatten a list of lists?
(3 answers)
Closed 5 years ago.
I got the following y nested list :
x1=c(12,54,2)
x2=c(2,88,1)
x3=c(4,8)
y=list()
y[[1]]=x1
y[[2]]=list(x2,x3)
y
[[1]]
[1] 12 54 2
[[2]]
[[2]][[1]]
[1] 2 88 1
[[2]][[2]]
[1] 4 8
I would like to extract all elements from this nested list and put them into a one level list, so my expected result should be :
y_one_level_list
[[1]]
[1] 12 54 2
[[2]]
[1] 2 88 1
[[3]]
[1] 4 8
Obviously ma real problem involve a deeper nested list, how would you solve it? I tried rapply but I failed.
Try lapply together with rapply:
lapply(rapply(y, enquote, how="unlist"), eval)
#[[1]]
#[1] 12 54 2
#[[2]]
#[1] 2 88 1
#[[3]]
#[1] 4 8
It does work for deeper lists either.
You can try this:
flatten <- function(lst) {
do.call(c, lapply(lst, function(x) if(is.list(x)) flatten(x) else list(x)))
}
flatten(y)
#[[1]]
#[1] 12 54 2
#[[2]]
#[1] 2 88 1
#[[3]]
#[1] 4 8
Related
I have a list of three different types of datasets, with ten datasets in each type. It looks like this:
mat1 <- replicate(n=10,data.frame(matrix(data=rnorm(20,0,1),nrow=5,ncol=5)),simplify=FALSE)
mat2 <- replicate(n=10,data.frame(matrix(data=rnorm(20,0,1),nrow=5,ncol=5)),simplify=FALSE)
mat3 <- replicate(n=10,data.frame(matrix(data=rnorm(20,0,1),nrow=5,ncol=5)),simplify=FALSE)
combined <- list(mat1,mat2,mat3)
I want to apply the same function to each of the datasets, but I can't figure out how to access them. I tried using map from purrr, but it only applies it to the first one in the list:
map(combined[[i]],~length(.))
[[1]]
[1] 5
[[2]]
[1] 5
[[3]]
[1] 5
[[4]]
[1] 5
[[5]]
[1] 5
[[6]]
[1] 5
[[7]]
[1] 5
[[8]]
[1] 5
[[9]]
[1] 5
[[10]]
[1] 5
How can I apply a function to all datasets in a nested list?
*The function is more complex than length - it's a function from another package that I need to access using ~function
You can apply lengths on each list in combined :
lapply(combined, lengths)
#[[1]]
# [1] 5 5 5 5 5 5 5 5 5 5
#[[2]]
# [1] 5 5 5 5 5 5 5 5 5 5
#[[3]]
# [1] 5 5 5 5 5 5 5 5 5 5
Using purrr's map :
purrr::map(combined, lengths)
If length is just an example and you want a general way to apply a function to each nested list you may use nested lapply :
lapply(combined, function(x) lapply(x, function(y) length(y)))
Or use rapply :
rapply(combined, length, how = 'list')
Good afternoon !
I'm wanting to transform a list like the following :
list_1= list(c(1,30,25),c(51,70),c(102,130,125))
to be :
list_2=list(c(1,2,3),c(4,5),c(6,7,8))
I know that we can retrieve list_1 lengths with :
lengths(list_1)
3 2 3
The list_2 represent indices of list_1 elements ( in case we unlist them ) .
I hope my question is clear , thank you for help in advance !
Using split.
ll <- lengths(list_1)
unname(split(seq(unlist(list_1)), rep(seq(ll), ll)))
# [[1]]
# [1] 1 2 3
#
# [[2]]
# [1] 4 5
#
# [[3]]
# [1] 6 7 8
An option with relist
relist(seq_along(unlist(list_1)), skeleton = list_1)
#[[1]]
#[1] 1 2 3
#[[2]]
#[1] 4 5
#[[3]]
#[1] 6 7 8
I have a list of values called squares and would like to replace all values which are 0 to a 40.
I tried:
replace(squares, squares==0, 40)
but the list remains unchanged
If it is a list, then loop through the list with lapply and use replace
squares <- lapply(squares, function(x) replace(x, x==0, 40))
squares
#[[1]]
#[1] 40 1 2 3 4 5
#[[2]]
#[1] 1 2 3 4 5 6
#[[3]]
#[1] 40 1 2 3
data
squares <- list(0:5, 1:6, 0:3)
I think for this purpose, you can just treat it as if it were a vector as follows:
squares=list(2,4,6,0,8,0,10,20)
squares[squares==0]=40
Output:
[[1]]
[1] 2
[[2]]
[1] 4
[[3]]
[1] 6
[[4]]
[1] 40
[[5]]
[1] 8
[[6]]
[1] 40
[[7]]
[1] 10
[[8]]
[1] 20
This is what I've got (a list):
>head(indexes)
[[1]]
numeric(0)
[[2]]
[1] 12
[[3]]
[1] 13
[[4]]
[1] 2 3
[[5]]
[1] 25
[[6]]
[1] 26
> all(vapply(indexes, is.numeric, TRUE)) # (note that..)
[1] TRUE
.. and this is what I want (same information for me):
>head(res,6)
[,1] [,2]
[1,] 2 12
[2,] 3 13
[3,] 4 2
[4,] 4 3
[5,] 5 25
[6,] 6 36
Is there a clever way to do this?
I tried a trick with naming the list:
names(indexes) <- 1:lenght(indexes)
res <- c(indexes, recursive=TRUE)
res <- cbind(as.integer(names(res)), res)
But R (such a kind damn kid!) breaks everything down by renaming the identical rows in an ambiguous fashion:
>head(res)
res
2 2 2
3 3 3
41 41 2
42 42 3
5 5 5
6 6 6
# ... (think about what happens around lines 3675.. 41158..)
.. if this was the clever way, how do I prevent the renaming?
Wops! Okay, nailed it:
res <- cbind(
rep(1:length(indexes), vapply(indexes,length,1)),
c(indexes,recursive=TRUE)
)
.. just tell me if anyone found a better way, then :)
This question already has answers here:
Create grouping variable for consecutive sequences and split vector
(5 answers)
Closed 5 years ago.
The following vector x contains the two sequences 1:4 and 6:7, among other non-sequential digits.
x <- c(7, 1:4, 6:7, 9)
I'd like to split x by its sequences, so that the result is a list like the following.
# [[1]]
# [1] 7
#
# [[2]]
# [1] 1 2 3 4
#
# [[3]]
# [1] 6 7
#
# [[4]]
# [1] 9
Is there a quick and simple way to do this?
I've tried
split(x, c(0, diff(x)))
which gets close, but I don't feel like appending 0 to the differenced vector is the right way to go. Using findInterval didn't work either.
split(x, cumsum(c(TRUE, diff(x)!=1)))
#$`1`
#[1] 7
#
#$`2`
#[1] 1 2 3 4
#
#$`3`
#[1] 6 7
#
#$`4`
#[1] 9
Just for fun, you can make use of Carl Witthoft's seqle function from his "cgwtools" package. (It's not going to be anywhere near as efficient as Roland's answer.)
library(cgwtools)
## Here's what seqle does...
## It's like rle, but for sequences
seqle(x)
# Run Length Encoding
# lengths: int [1:4] 1 4 2 1
# values : num [1:4] 7 1 6 9
y <- seqle(x)
split(x, rep(seq_along(y$lengths), y$lengths))
# $`1`
# [1] 7
#
# $`2`
# [1] 1 2 3 4
#
# $`3`
# [1] 6 7
#
# $`4`
# [1] 9