Reputation: 1773
I have two lists x and y:
x <- list(id1 = list(a = list(t = 5)), id2 = list(a = list(t = 1), b = list(t = 3)), id3 = list(a = list(t = 1), b = list(t = 2)))
y <- list(b = list(k = 7))
I need to modify x list and add corresponding "b" elements from y list to obtain z list:
z <- list(id1 = list(a = list(t = 5)), id2 = list(a = list(t = 1), b = list(t = 3, k = 7)),
id3 = list(a = list(t = 1), b = list(t = 2, k = 7)))
I try to use list_modify(x, y)
and list_merge(x, !!!y)
from purrr
package but obtain wrong result.
How to do this in R?
Upvotes: 1
Views: 314
Reputation: 86
purrr::list_merge works as expected, but when the lists are named it uses the names to find the positions for merging, and your y isn't named properly with id2/id3 for it to merge.
To use list_merge:
y <- list(id2 = list(b = list(k = 7)), id3 = list(b = list(k = 7)))
z2 <- list_merge(x, !!!y)
identical(z, z2)
[1] TRUE
Upvotes: 0
Reputation: 13691
An alternative solution using map_if
: apply list_merge
to every element in the original list that has at least one subname in common with y
:
map_if(x, ~any(names(.) %in% names(y)), list_merge, !!!y)
Upvotes: 0
Reputation: 173858
In this case you could do:
result <- lapply(x, function(i) {
if("b" %in% names(i)) i$b <- append(i$b, y$b); i;
})
Such that
identical(result, z)
#> [1] TRUE
Upvotes: 2
Reputation: 21947
It's not particularly elegant, but you could use a loop to do this. The loop goes over the elements in x
and within that, the elements in y
. If there is an element in x
with the same name as an element in y
, the two are concatenated together in z
, otherwise, z
is just x
. Depending on the scale of the real problem, this may be too slow, and perhaps someone can provide a tidy alternative.
z <- vector(mode="list", length = length(x))
for(i in 1:length(x)){
for(j in 1:length(y)){
z[[i]] <- x[[i]]
if(names(y)[j] %in% names(x[[i]])){
z[[i]][[names(y)[j]]] <- c(x[[i]][[names(y)[j]]], y[[j]])
}else{
}
names(z) <- names(x)
}
}
Upvotes: 0