#r #purrr
#r #purrr
Вопрос:
У меня есть два списка x и 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))
Мне нужно изменить список x и добавить соответствующие элементы «b» из списка y, чтобы получить список z:
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)))
Я пытаюсь использовать list_modify(x, y)
и list_merge(x, !!!y)
из purrr
пакета, но получаю неверный результат.
Как это сделать в R?
Ответ №1:
В этом случае вы могли бы сделать:
result <- lapply(x, function(i) {
if("b" %in% names(i)) i$b <- append(i$b, y$b); i;
})
Такой, что
identical(result, z)
#> [1] TRUE
Ответ №2:
Это не особенно элегантно, но вы могли бы использовать цикл для этого. Цикл проходит по элементам внутри x
и внутри, элементы внутри y
. Если есть элемент in x
с тем же именем, что и элемент in y
, они объединяются вместе в z
, в противном случае z
это просто x
. В зависимости от масштаба реальной проблемы это может быть слишком медленно, и, возможно, кто-то может предоставить аккуратную альтернативу.
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)
}
}
Ответ №3:
Альтернативное решение с использованием map_if
: применить list_merge
к каждому элементу в исходном списке, который имеет хотя бы одно общее с y
:
map_if(x, ~any(names(.) %in% names(y)), list_merge, !!!y)
Ответ №4:
purrr::list_merge работает, как и ожидалось, но когда спискам присваиваются имена, он использует имена для поиска позиций для слияния, и ваш y неправильно назван с помощью id2 / id3 для слияния.
Чтобы использовать 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] ВЕРНО