I have a list structure which represents a table being handed to me like this
> l = list(list(1, 4), list(2, 5), list(3, 6))
> str(l)
List of 3
$ :Lis
A second base R method using Reduce
and split
in two lines is
# bind lists together into a matrix (of lists)
temp <- Reduce(rbind, l)
# split unlisted values using indices of columns
split(unlist(temp), col(temp))
$`1`
[1] 1 2 3
$`2`
[1] 4 5 6
this assumes that each list item has the same number of elements. You can add names in the second line if desired with setNames
:
setNames(split(unlist(temp), col(temp)), c("x", "y"))
For the specific example, you can use this pretty simple approach:
split(unlist(l), c("x", "y"))
#$x
#[1] 1 2 3
#
#$y
#[1] 4 5 6
It recycles the x-y vector and splits on that.
To generalize this to "n" elements in each list, you can use:
l = list(list(1, 4, 5), list(2, 5, 5), list(3, 6, 5)) # larger test case
split(unlist(l, use.names = FALSE), paste0("x", seq_len(length(l[[1L]]))))
# $x1
# [1] 1 2 3
#
# $x2
# [1] 4 5 6
#
# $x3
# [1] 5 5 5
This assumes, that all the list elements on the top-level of l
have the same length, as in your example.
The sapply
extracts the ith element of each component of l
creating a numeric vector and the lapply
applies it over 1:2 (since there are k=2 elements in each component of l
).
If you know that k is 2 then the first line could be replaced with k <- 2
. Also note that in the first line we divide by max(..., 1) to avoid dividing by 0 in the case that l
is a zero length list.
The code below gives the output shown in the question; however, the subject refers to nested lists and if we wanted a list of lists rather than a list of numeric vectors then we could replace sapply
with lapply
.
k <- length(unlist(l)) / max(length(l) , 1)
lapply(seq_len(k), function(i) sapply(l, "[[", i))
giving:
[[1]]
[1] 1 2 3
[[2]]
[1] 4 5 6
Here is one idea with unlisting each list i.e.
split(do.call(cbind, lapply(l, unlist)), seq(unique(lengths(l))))
which gives,
$`1` [1] 1 2 3 $`2` [1] 4 5 6
We can use
library(tidyverse)
r1 <- l %>%
transpose %>%
map(unlist)
identical(r1, unname(lt))
#[1] TRUE