【问题标题】:How do I loop in a list and access both names and attributes?如何循环访问列表并访问名称和属性?
【发布时间】:2011-09-20 07:25:41
【问题描述】:

我正在对列表的元素应用一个函数。

列表有names,因此从某种意义上说,每个元素都有自己的名称,但是一旦lapply 函数已经从列表中提取/分离了元素,我该如何访问它?

一些虚构的数据(作为内部函数我在这里滥用dput):

r <- list(a=structure(1:4, unit="test"), b='abc')
lapply(r, dput)

我在这里观察到dput 接收列表中的对象,就像使用[[ 访问一样,被剥夺了它们在包含列表中的名称。

所以我想我会放弃使用 apply 系列中的函数并编写一个循环的想法,但我并不特别喜欢这个想法,它迫使我构造完整函数的结果。

result <- list()
for (name in names(r)) {
  print(name)
  result[[name]] <- dput(r[[name]])
}
result

有什么深刻的想法吗?

【问题讨论】:

    标签: r


    【解决方案1】:

    您可以在仍然使用lapply 的同时模拟循环背后的想法,方法是将一个数字向量传递给lapply,然后使用它作为索引从您想要的列表中提取元素。这可能没有意义,但希望这个例子能说明我的意思:

    lapply(seq_along(r), function(i)dput(r[i]))
    
    structure(list(a = structure(1:4, unit = "test")), .Names = "a")
    structure(list(b = "abc"), .Names = "b")
    [[1]]
    [[1]]$a
    [1] 1 2 3 4
    attr(,"unit")
    [1] "test"
    
    
    
    [[2]]
    [[2]]$b
    [1] "abc"
    

    关键思想是seq_along(x) 返回一个与x 长度相同的序列。例如:

    > seq_along(r)
    [1] 1 2
    

    更多详情请参阅?seq_along


    编辑

    这似乎比按名称索引要快一点:

    library(rbenchmark)
    benchmark(
      xx <- lapply(names(r), function(i)dput(r[i])),
      yy <- lapply(seq_along(r), function(i)dput(r[i])),
      replications=10000)
    
                                                    test replications elapsed relative user.self
    1     xx <- lapply(names(r), function(i) dput(r[i]))        10000    1.95 1.026316      1.70
    2 yy <- lapply(seq_along(r), function(i) dput(r[i]))        10000    1.90 1.000000      1.66
      sys.self user.child sys.child
    1     0.00         NA        NA
    2     0.01         NA        NA
    

    【讨论】:

    • 按数字索引访问是否比按名称访问更快?
    • 好的,它比循环更具可读性,并且避免了额外的result 变量的需要。所以我按照你的提示,谢谢!这里唯一的变化是我更喜欢lapply(names(r), function(name) dput(r[[name]]))。我正在等待接受答案,看看是否有更多想法出现。
    • 只有非常。我用一些rbenchmark 结果编辑了我的答案
    • 我喜欢你对lapply(names(r), ...) 的想法。我会更新我自己的内部设计成语!谢谢。
    • 第二件事。在切换到mapply之前,我曾经使用lapply,然后我使用以下语法(我认为它更具可读性):lapply(names(x), function(name, value=x[[name]]) {...})
    【解决方案2】:

    你可以使用mapply:

    dummy <- function(value, name) {
        list(
            name_of_element = name,
            value_of_element = value
        )
    }
    str(mapply(dummy, r, names(r), SIMPLIFY=FALSE))
    # List of 2
     # $ a:List of 2
      # ..$ name_of_element : chr "a"
      # ..$ value_of_element: atomic [1:4] 1 2 3 4
      # .. ..- attr(*, "unit")= chr "test"
     # $ b:List of 2
      # ..$ name_of_element : chr "b"
      # ..$ value_of_element: chr "abc"
    

    【讨论】:

    • 不太确定是否更具可读性,但这里慢了 70%:library(rbenchmark); benchmark( xx &lt;- lapply(names(r), function(i)all(r[[i]] == 0)), yy &lt;- lapply(seq_along(r), function(i)all(r[[i]]==0)), zz &lt;- mapply(function(i,n)all(i==0), r, names(r), SIMPLIFY=FALSE), replications=10000)
    猜你喜欢
    • 2016-08-18
    • 1970-01-01
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    相关资源
    最近更新 更多