首页 > 解决方案 > R:使用 data.table 访问列表列中的元素

问题描述

我正在使用 data.table 来存储一大堆对象,并且我想访问其中一个对象,但它总是返回包装在列表中的结果。

library(data.table)

a1 = hist(1:10)
a2 = hist(2:11)
a3 = hist(3:12)
a4 = hist(4:13)
a5 = hist(5:14)
a6 = hist(6:15)

a = list(a1,a2,a3,a4,a5,a6)
i = c(1,1,1,2,2,2)
j = c(1,2,3,1,2,3)

dt = data.table(i = i, j = j, a = a)
class(dt[i == 1 & j == 1, a]) # hist inside a list of length 1

我希望上一行返回对象本身(只是直方图),如下所示:

class(a1) # just the hist

显然我可以这样做:

dt[i == 1 & j == 1, a][[1]]

但每次都这样做似乎很不雅。有什么方法可以使用 data.table 中的语法来实现这一点?注意:还有另一个名称非常相似的问题,但它提出的问题更复杂。

标签: rarrayslistdata.table

解决方案


我认为你的方法是唯一的方法,或者我也会这样做dt[i == 1 & j == 1, a[[1]] ]

您可以编写一个辅助函数,例如

get_a = function(ii,jj) dt[.(ii,jj), on=.(i,j), mult="first", a[[1]]]

但是如果你写了一个匹配表的 0 或 2+ 行的子集,你可能会后悔:

get_a(1,1)   # works as expected
get_a(1,4)   # returns NULL
get_a(1,1:2) # returns only (1,1)

如果您想避免这种情况,可以添加基于.N...的检查

get_listcol = function(..., d, list_col, join_cols = names(list(...)), mult = FALSE){
  d[list(...), on=join_cols, nomatch=0, {
    if (.N == 0L){
      stop("No matches found.")
    } else if (.N == 1L){
      .SD[[1]][[1]]
    } else {
      if (mult){
        .SD[[1]]
      } else {
        stop("Multiple matches found.")
      }
    }
  }, .SDcols=list_col]
}

# usage
get_a2 = function(ii, jj) get_listcol(i = ii, j = jj, d = dt, list_col = "a")
get_a2(1,1)   # works as expected
get_a2(1,4)   # error
get_a2(1,1:2) # error

推荐阅读