【问题标题】:Reduce a nested list with varying length减少具有不同长度的嵌套列表
【发布时间】:2015-05-07 19:41:44
【问题描述】:

假设我有一个清单:

  mylist=list(list(data.frame(a=3,b=2,c=4),data.frame(d=5,e=6,h=8),data.frame(k=2,e=3,b=5,m=5)),
              list(data.frame(a=32,b=22,c=42),data.frame(d=5,e=63,h=82),data.frame(k=2,e=33,b=5,m=5)),
              list(data.frame(a=33,b=21,k=41,c=41),data.frame(d=5,e=61,h=80),data.frame(k=22,e=3,b=5,m=5)))

然后我尝试通过cbind列表的每个元素获取一个新列表,例如 cbind mylist[[1]][[1]]withmylist[[2]][[1]]andmylist[[3]][[1]]

功能:

newlist=lapply(seq_along(mylist[[1]]), function(x){    
    newlist=Reduce("cbind",c(mylist[[1]][x],mylist[[-1]][x]))
    return(newlist)

})

I get:
Error in mylist[[-1]] : attempt to select more than one element  

但是如果列表只有:

mylistshort=mylist[-3]

想要的结果是:

[[1]]
  a b c  a  b  c a  b  k  c
1 3 2 4 32 22 42 33 21 41 41

[[2]]
  d e h d e  h  d e  h
1 5 6 8 5 63 82 5 61 80

[[3]]
  k e b m k e  b m k  e m
1 2 3 5 5 2 33 5 5 22 3 5

那么如何减少长度大于 2 的列表? 最好的问候

【问题讨论】:

    标签: r list reduce


    【解决方案1】:

    另一个想法:

    .mapply(cbind, mylist, NULL)
    #[[1]]
    #  a b c  a  b  c  a  b  k  c
    #1 3 2 4 32 22 42 33 21 41 41
    #
    #[[2]]
    #  d e h d  e  h d  e  h
    #1 5 6 8 5 63 82 5 61 80
    #
    #[[3]]
    #  k e b m k  e b m  k e b m
    #1 2 3 5 5 2 33 5 5 22 3 5 5
    

    编辑: 一些cmets

    基本上,您正在寻找“矢量化”cbind。您可以为此使用 for 循环,但 R 有一个内置的“矢量化”工具:mapply(不一定更快,但更干净)。对于特定数量的参数,您可以使用 mapply,如下所示:

    mapply(function(x, y, z) cbind(x, y, z), mylist[[1]], mylist[[2]], mylist[[3]])
    

    但是,您也可以传递“可变长度参数”(...) 以使其更实用:

    mapply(function(...) cbind(...), mylist[[1]], mylist[[2]], mylist[[3]])
    

    cbind 是为知道如何处理 ... 参数而构建的:

    mapply(cbind, mylist[[1]], mylist[[2]], mylist[[3]])
    

    这仍然不灵活,因为您必须指定每个参数,因为mapply 只接受...do.call 在“列表”中有函数参数的情况下很方便:

    do.call(mapply, c(cbind, mylist))
    

    R,有一个带点的mapply,它接受它的... 参数作为列表,看起来更酷,并且可以替换do.call

    .mapply(FUN = cbind, dots = mylist, MoreArgs = NULL)
    

    【讨论】:

    • 很好的答案!学到了新东西:)
    【解决方案2】:

    您按照 Ananda Mahto 的建议执行以下操作(使用 Reduce):

    myfun <- function(x) Reduce(cbind,x)
    apply(do.call(cbind, mylist), 1, myfun)
    

    我原来的答案(包括data.table

    require(data.table)
    setDT(mylist)
    myfun <- function(x) Reduce(cbind,x)
    apply(mylist,1, myfun)
    

    结果:

    > apply(mylist,1, myfun)
    [[1]]
      a b c  a  b  c  a  b  k  c
    1 3 2 4 32 22 42 33 21 41 41
    
    [[2]]
      d e h d  e  h d  e  h
    1 5 6 8 5 63 82 5 61 80
    
    [[3]]
      k e b m k  e b m  k e b m
    1 2 3 5 5 2 33 5 5 22 3 5 5
    

    【讨论】:

    • 谢谢!!很好的解决方案。
    • 很好奇,在你的答案中使用data.table 的目的是什么?
    • @Floo0 setDT 版本具有创新性。 +1
    • 老实说:我知道但不知道我如何才能拥有data.framematrixarray 或包含data.frame 的类似条目。 data.table 可以做到这一点。这就是我使用setDT 的原因。也许有更优雅的解决方案...
    • @Floo0,如果你想在基地做这个,你可以做apply(do.call(cbind, mylist), 1, myfun)
    【解决方案3】:

    这是一种使用老式 do.call() 而不是 Reduce() 的方法。

    lapply(
        seq_along(mylist), 
        function(ii) do.call(cbind, vapply(mylist, "[", list(1), ii))
    )
    
    # [[1]]
    # a b c  a  b  c  a  b  k  c
    # 1 3 2 4 32 22 42 33 21 41 41
    # 
    # [[2]]
    # d e h d  e  h d  e  h
    # 1 5 6 8 5 63 82 5 61 80
    # 
    # [[3]]
    # k e b m k  e b m  k e b m
    # 1 2 3 5 5 2 33 5 5 22 3 5 5
    

    【讨论】:

    • 谢谢,漂亮...虽然我可以使用 reduce...如果没有其他人会找到 Reduce 解决方案,我会接受您的回答。
    • @AnandaMahto 好吧,它没有,认为Reduce 有解决方案...
    • Reduce() 很好,但如果您实际上不使用它来执行它的设计任务,它可能会比其他功能慢
    【解决方案4】:

    另一种方法是使用unlist,如下所示:

    un_mylist <- unlist(mylist, recursive = FALSE)
    ind <- lapply(seq_along(mylist), seq, to = length(un_mylist), by = length(mylist))
    myfun <- function(ind, x){
      Reduce(cbind,x[ind])
    }
    lapply(ind, myfun, x = un_mylist)
    

    这种方法假定所有嵌套列表确实具有相同的长度: sapply(mylist, length)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-15
      • 2018-12-02
      • 2016-06-21
      • 1970-01-01
      • 2018-07-16
      • 1970-01-01
      相关资源
      最近更新 更多