rbinding data.table 列表的列表

rbinding a list of list of data.table

这听起来很愚蠢,但我有一个 data.table 的清单列表

list(list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)),
     list(table1=data.table(A1=-1:3, B1=-2:2),
          table2=data.table(A2=-3:1, B2=-4:0)),
     list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)))

我想rbind每个tableX在一起,和return一个列表data.table,即

list(table1=data.table(A1=c(1:3, -1:3, 1:3), B1=c(2:4, -2:2, 2:4)),
     table2=data.table(A2=c(3:1, -3:1, 3:1), B2=c(4:2, -4:0, 4:2)))

在现实世界的场景中,输入将是一个包含数千个列表的列表,每个列表有数十个 data.tables,每个列表有数百列,因此硬编码不是一种选择。

它可能不是最优雅或最有效的解决方案,但我的建议是首先为给定数字 X 创建一个仅包含 tableX 的列表。然后在此列表上执行 rbind,并将输出放入正确索引的新列表中。您可能需要根据实际数据的具体情况进行修改——我假设列表中的每个列表都有每个 tableX,并且它们是有序的。

见下文:

library(data.table)
library(testthat)

dt.list <- list(list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)),
     list(table1=data.table(A1=-1:3, B1=-2:2),
          table2=data.table(A2=-3:1, B2=-4:0)),
     list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)))

dt.output <- 
  list(table1=data.table(A1=c(1:3, -1:3, 1:3), B1=c(2:4, -2:2, 2:4)),
     table2=data.table(A2=c(3:1, -3:1, 3:1), B2=c(4:2, -4:0, 4:2)))


# Extract number of tableX's -- assuming same number in each list element.
mylist <- vector(mode = "list", length = length(dt.list[[1]]))
for (li in seq(length(mylist))) {
  # Extract tableXs, put into list.
  list.tableX <- lapply(dt.list, function(x) {
                    return(x[[li]])
                  })
  # Use rbind to put together
  mylist[[li]] <- do.call("rbind", list.tableX)
  names(mylist)[li] <- paste0("table", li)
}

testthat::expect_identical(dt.output, mylist)

一个选择是先purrr::transpose你的列表,然后使用rbindlistMap

out <- Map(data.table::rbindlist, purrr::transpose(l))

检查输出

identical(out,
          list(table1=data.table(A1=c(1:3, -1:3, 1:3), B1=c(2:4, -2:2, 2:4)),
               table2=data.table(A2=c(3:1, -3:1, 3:1), B2=c(4:2, -4:0, 4:2))))
#[1] TRUE

数据

l <- list(list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)),
     list(table1=data.table(A1=-1:3, B1=-2:2),
          table2=data.table(A2=-3:1, B2=-4:0)),
     list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)))

考虑使用具有提取功能的基础 R 应用系列解决方案,[[:

table_names <- unlist(unique(lapply(my_original_list, names)))

final_list <- sapply(table_names, function(t) 
                       rbindlist(lapply(my_original_list, `[[`, t)),
                     simplify=FALSE)

final_list

我的第一个想法是先 transpose,但转置的计算量可能很大。可以简洁地使用 purrr::map_dfr:

的正常索引
library(purrr)
map(1:2, ~ map_dfr(l, .))

这是一个基本解决方案(rbindlist

library(data.table)

apply(simplify2array(lst), 1, rbindlist)

结果与预期相同:

identical(list(table1=data.table(A1=c(1:3, -1:3, 1:3), B1=c(2:4, -2:2, 2:4)),
              table2=data.table(A2=c(3:1, -3:1, 3:1), B2=c(4:2, -4:0, 4:2))),
          apply(simplify2array(lst), 1, rbindlist))

# [1] TRUE