Передать список списков
У меня есть список, который содержит записи списка, и мне нужно транспонировать структуру. Первоначальная структура является прямоугольной, но имена в подписях не совпадают.
Вот пример:
ax <- data.frame(a=1,x=2)
ay <- data.frame(a=3,y=4)
bw <- data.frame(b=5,w=6)
bz <- data.frame(b=7,z=8)
before <- list( a=list(x=ax, y=ay), b=list(w=bw, z=bz))
Что я хочу:
after <- list(w.x=list(a=ax, b=bw), y.z=list(a=ay, b=bz))
Меня не интересуют имена результирующего списка (на любом уровне).
Ясно, что это можно сделать явно:
after <- list(x.w=list(a=before$a$x, b=before$b$w), y.z=list(a=before$a$y, b=before$b$z))
но это уродливо и работает только для структуры 2x2. Какой идиоматический способ сделать это?
Ответы
Ответ 1
Следующий фрагмент кода создает список с I-го элемента каждого списка в before
тем:
lapply(before, "[[", i)
Теперь вам просто нужно сделать
n <- length(before[[1]]) # assuming all lists in before have the same length
lapply(1:n, function(i) lapply(before, "[[", i))
и он должен дать вам то, что вы хотите. Он не очень эффективен (перемещает каждый список много раз), и вы, вероятно, можете сделать его более эффективным, указав на текущие элементы списка, поэтому, пожалуйста, решите, достаточно ли это для вас.
Ответ 2
purrr
пакет purrr
делает этот процесс очень простым:
library(purrr)
before %>% transpose()
## $x
## $x$a
## a x
## 1 1 2
##
## $x$b
## b w
## 1 5 6
##
##
## $y
## $y$a
## a y
## 1 3 4
##
## $y$b
## b z
## 1 7 8
Ответ 3
Здесь другая идея - используйте тот факт, что data.table
может хранить data.frame
(на самом деле, учитывая ваш вопрос, возможно, вам даже не нужно работать со списками списков и просто работать с data.table
):
library(data.table)
dt = as.data.table(before)
after = as.list(data.table(t(dt)))
Ответ 4
Хотя это старый вопрос, я нашел его во время поиска той же проблемы, а второй удар по google имел гораздо более элегантное решение, на мой взгляд:
list_of_lists <- list(a=list(x="ax", y="ay"), b=list(w="bw", z="bz"))
new <- do.call(rbind, list_of_lists)
new
теперь представляет собой прямоугольную структуру, странный объект: список с атрибутом измерения. Он работает с как можно большим количеством элементов, если каждый подсписчик имеет одинаковую длину. Чтобы изменить его на более распространенный R-объект, можно было бы, например, создать такую матрицу:
new.dims <- dim(new)
matrix(new,nrow = new.dims[1])
new.dims
необходимо сохранить, так как функция matrix()
удаляет атрибут списка. Другой путь:
new <- do.call(c, new)
dim(new) <- new.dims
Теперь вы можете, например, преобразовать его в data.frame с as.data.frame()
и разбить его на столбцы или выполнить операции с колонками. Прежде чем вы это сделаете, вы также можете изменить атрибут dim
, который соответствует вашим потребностям.
Ответ 5
Я столкнулся с этой проблемой, но мне нужно решение, в котором сохранялись имена каждого элемента. Решение, которое я придумал, должно также работать, когда вспомогательные списки не имеют одинаковой длины.
invertList = function(l){
elemnames = NULL
for (i in seq_along(l)){
elemnames = c(elemnames, names(l[[i]]))
}
elemnames = unique(elemnames)
res = list()
for (i in seq_along(elemnames)){
res[[elemnames[i]]] = list()
for (j in seq_along(l)){
if(exists(elemnames[i], l[[j]], inherits = F)){
res[[i]][[names(l)[j]]] = l[[names(l)[j]]][[elemnames[i]]]
}
}
}
res
}