Unlist LAST level of a list in R - r

I have a list of list like ll:
ll <- list(a = list(data.frame(c = 1, d = 2), data.frame(h = 3, j = 4)), b = list(data.frame(c = 5, d = 6), data.frame(h = 7, j = 9)))
I want to unnest/unlist the last level of the structure (the interior list). Note that every list contains the same structure. I want to obtain lj:
lj <- list(a = (data.frame(c = 1, d = 2, h = 3, j = 4)), b = data.frame(c = 5, d = 6, h = 7, j = 9))
I have tried the following code without any success:
lj_not_success <- unlist(ll, recursive = F)
However, this code unlists the FIRST level, not the LAST one.
Any clue?

We may need to cbind the inner list elements instead of unlisting as the expected output is a also a list of data.frames
ll_new <- lapply(ll, function(x) do.call(cbind, x))
-checking
> identical(lj, ll_new)
[1] TRUE

Related

Transform an atomic vector to list (inverse of purrr::simplify())

TLDR:
I need a simple way to transform c(a = 1, a = 3, a = 6) into list(c(a = 1), c(a = 3), c(a = 6)).
Longer version:
I am using the function purrr::accumulate(), where the output of each element is an atomic vector of length greater or equal to one. When the length is one, purrr::accumulate() simplifies the whole output to an atomic vector, instead of a list.
Is there a simple way to undo or avoid this? Unfortunately, as.list() does not give me what I want.
Simple example to illustrate:
purrr::accumulate(2:3, `+`, .init = c(a=1, b=2))
gives me
list(c(a = 1, b = 2), c(a = 3, b = 4), c(a = 6, b = 7))
as expected. However,
purrr::accumulate(2:3, `+`, .init = c(a=1))
gives me
c(a = 1, a = 3, a = 6)
when I instead want
list(c(a = 1), c(a = 3), c(a = 6))
You could try
c(a = 1, a = 3, a = 6) %>% map(~setNames(.x, nm = "a"))
$a
a
1
$a
a
3
$a
a
6
or you can also remove the list names with set_names()
c(a = 1, a = 3, a = 6) %>% map(~setNames(.x, nm = "a")) %>%
set_names("")
[[1]]
a
1
[[2]]
a
3
[[3]]
a
6

Providing the correct match for a list in a list of lists in R

I have a list of lists in R:
a <- list(x=0, y=c(1,2,3), z=4)
b <- list(x=1, y=c(1,2,3), z=44)
c <- list(x=2, y=c(1,2,3), z=444)
L <- list(a,b,c)
For a given list, say
l <- list(x=0, y=c(1,2,3), z=4)
I know want to find the correct index of L where we find the corresponding list that equals l.
Of course, I can use a loop, but since Lis very large, I need a faster solution.
(And is a list even the right choice here?)
We can use stack with identical from base R
which(sapply(L, function(x) identical(stack(l), stack(x))))
#[1] 1
Or more compactly
which(sapply(L, identical, l))
#[1] 1
Using mapply to compare each element one by one with l. If you unlist it, all should be TRUE. Using which around an sapply finally gives the number of the matching element.
f <- function(x) all(unlist(mapply(`==`, x, l)))
which(sapply(L, f))
# [1] 1
Data:
L <- list(list(x = 0, y = c(1, 2, 3), z = 4), list(x = 1, y = c(1,
2, 3), z = 44), list(x = 2, y = c(1, 2, 3), z = 444))
l <- list(x = 0, y = c(1, 2, 3), z = 4)
Perhaps you can try mapply like below
> which(mapply(identical, L, list(l)))
[1] 1

Search a vector in a specific element of a nested list in R

To explain what I want to do exactly, I will use the following example:
a = list(x = 5, y = c(11, 12, 13))
b = list(x = 4.7, y = c(112, 5, 2))
c = list(x = 77, y = c(5, 1, 1))
d = list(x = 5, y = c(22, 11, 43))
test_list = list(a, b, c, d)
I have a nested list: test_list. I would like to search vector 5 only in element x in the tested_list, and return the indices of the list, e.g., here as c(1,4).
Thanks a lot.
I would try with lapply like here:
a = list(x = 5, y = c(11, 12, 13))
b = list(x = 4.7, y = c(112, 5, 2))
c = list(x = 77, y = c(5, 1, 1))
d = list(x = 5, y = c(22, 11, 43))
test_list = list(a, b, c, d)
which(unlist(lapply(test_list, function(x) {
x$x == 5
})))
First you choose x then for 5 then unlist and then check which are TRUE.
Try:
which(vapply(test_list, function(x) x[["x"]] == 5, logical(1)))
Similarly, using purrr:
which(map_lgl(test_list, ~ pluck(., "x") == 5))
[1] 1 4
As 'x' is of length 1 in each list element, it may be better to do the comparison at once after extracting the element
which(sapply(test_list, `[[`, 'x')==5)
#[1] 1 4

Unpack a list by duplicating elements longer than 1

I have the following list that I wish to unpack (aka expand) using only base R.
For example, I want to turn this:
b <- list(a = c(1, 2), b = 1, d = c(5, 7))
into the equivalent of:
list(a = 1, a = 2, b = 1, d = 5, d = 7)
I have this function that works if only one named element has length > 1 but not if there are multiple elements:
expand_list <- function(listx){
long_elements <- as.numeric(which(lapply(listx, length) > 1))
short_elements <- as.numeric(which(lapply(listx, length) == 1))
res <- lapply(long_elements, function(x){
as.list(setNames(listx[[x]], rep(names(listx)[x], length(listx[[x]]))))
})
expanded_elements <- res[[1]]
c(listx[short_elements], expanded_elements)
}
expand_list(b)
You can use stack followed by setNames to achieve that
y <- list(a = c(1, 2), b = 1, c = 2, d = c(5, 7))
x <- stack(y)
as.list(setNames(x$values, x$ind))

Subset list, keep names

I have list out like this:
u <- list(a = list(b = 1, c = 2),
x = list(k = list(ka = 1, kb = 3),
l = list(la = 1, la = 4)))
v <- list(a = list(b = 1, c = 2),
x = list(m = list(ma = 5, mb = 8),
n = list(na = 5, nb = 8)))
w <- list(a = list(b = 1, c = 2),
x = list(o = list(oa = 4, ob = 1),
p = list(pa = 8, pb = 0)))
out <- list(u, v, w)
I would like to create another list where there are elements k, l, m, n, o, p and names of the list elements are preserved. I found a solution, but looks sub-optimal:
x <- lapply(out, function(y) y[['x']])
o <- list()
for (a in x) {
o <- c(o, a)
}
> str(o, max.level = 1)
List of 6
$ k:List of 2
$ l:List of 2
$ m:List of 2
$ n:List of 2
$ o:List of 2
$ p:List of 2
Is there a better way?
The loop could be replaced with unlist:
res <- unlist( lapply(out,"[[","x"), recursive=FALSE)
identical(res,o)
# [1] TRUE
My lapply is the same as in the OP; it's just a shortcut.
As #akrun suggested, you could more closely mirror the OP's loop with
do.call("c", lapply(out, '[[', 'x'))

Resources