I have a list of lists 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 add one variable grp to each final list. This variable (grp) has to contain the name/value of each list. Therefore the new list of lists may look like ls:
ls <- list(a = list(data.frame(c = 1, d = 2, grp = 1), data.frame(h = 3, j = 4, grp = 2)), b = list(data.frame(c = 5, d = 6, grp = 1), data.frame(h = 7, j = 9, grp = 2)))
NOTE: The grp may not follow a sequence from 1:n. The approach I look for may be similar to the following one bind_rows(df, .id = 'grp')
. The only point is that in this case, I don´t want to row bind (at least not in this way but in this other Unlist LAST level of a list in R)
Any clue?
CodePudding user response:
From the post it seems the groups are defined iteratively for each nested list. We can use a seq_along
to create the groups, and apply this on each element of the list ll
.
base R
lapply(ll, \(.){
Map(function(i, n) {n$grp = i ; n}, seq_along(.), .)
})
$a
$a[[1]]
c d grp
1 1 2 1
$a[[2]]
h j grp
1 3 4 2
$b
$b[[1]]
c d grp
1 5 6 1
$b[[2]]
h j grp
1 7 9 2
purrr
map(ll, ~imap(.x, ~{.x$grp <- .y ; .x}))
For similar approaches using purely lapply
, mapply
or purrr::map
, see this SO post. In this approach the only difference with the expected result is the class of the vector, an integer
instead of a numeric
, see waldo::compare(ls, ll)
.
CodePudding user response:
You can simply cycle through the levels with lapply
setNames( lapply( 1:length(ll), function(x) lapply( 1:length(ll[[x]]),
function(y) cbind(ll[[x]][[y]],grp=y ) ) ), names(ll) )
$a
$a[[1]]
c d grp
1 1 2 1
$a[[2]]
h j grp
1 3 4 2
$b
$b[[1]]
c d grp
1 5 6 1
$b[[2]]
h j grp
1 7 9 2