【问题标题】:Access list element based on attribute value基于属性值的访问列表元素
【发布时间】:2018-05-09 21:18:50
【问题描述】:

假设我有一个列表,其元素具有属性,如下所示:

my_list <- list()

my_list[[1]] <- 1:10
my_list[[2]] <- 11:20
my_list[[3]] <- 21:30

attr(my_list[[1]], "att1") <- "a"
attr(my_list[[2]], "att1") <- "b"
attr(my_list[[3]], "att1") <- "c"

attr(my_list[[1]], "att2") <- "1"
attr(my_list[[2]], "att2") <- "2"
attr(my_list[[3]], "att2") <- "3"

现在,假设这个列表有数百个元素,我不知道列表中的哪个元素具有我想要的属性。但我知道我想要元素,比如 att1 == "b" 和 att2 == "2"(但我不知道它恰好对应于列表元素 2)。

在 R 中有没有办法查找列表中的哪些元素具有特定的属性组合?

【问题讨论】:

  • Filter(function(x) attr(x, "att1") == "b" &amp; attr(x, "att2") == "2", my_list)?或者sapply,如果你想知道每个元素的真/假...顺便说一句,如果你把它放在一个表中,查找会更容易。
  • 谢谢!这确实可以解决问题!我正在使用的包返回一堆交叉验证矩阵作为列表元素,其属性对应于调整参数——因此我正在寻找如何查找列表元素。

标签: r list attributes


【解决方案1】:

您可以使用Filter 过滤列表:

Filter(function(x) attr(x, "att1") == "b" & attr(x, "att2") == "2", my_list)

如果您希望元素是唯一的并且想要选择它,请在末尾添加[[1]]。


就个人而言,我会将数据放入表格中:

library(data.table)
myDT = data.table(
  att1 = sapply(my_list, attr, "att1"), 
  att2 = sapply(my_list, attr, "att2"),
  data = my_list
)

#    att1 att2               data
# 1:    a    1       1,2,3,4,5,6,
# 2:    b    2 11,12,13,14,15,16,
# 3:    c    3 21,22,23,24,25,26,

然后你可以验证 att1 + att2 唯一地固定一个元素

nrow(myDT) == uniqueN(myDT, by=c("att1", "att2"))
# [1] TRUE

并为子集编写一个辅助函数

setkey(myDT, att1, att2)
get_element = function(a1, a2) myDT[.(a1, a2), data[[1]]]

get_element("b", "2")
#  [1] 11 12 13 14 15 16 17 18 19 20
# attr(,"att1")
# [1] "b"
# attr(,"att2")
# [1] "2"

您可能还想查看 purrr 和 broom 包,它们为具有列表列的表提供不同的“tidyverse”语法。

【讨论】:

    【解决方案2】:

    @Frank 已经提供了一个很好的解决方案(答案背后有明确的逻辑)。我仍然想涵盖其他几个选项(同样,@Frank 在他的回答中已经暗示过)。

    选项#1:

    library(purrr)
    my_list %>% keep(~ attr(., "att1") == "b" & attr(., "att2") == "2")
    
    #[[1]]
    # [1] 11 12 13 14 15 16 17 18 19 20
    #attr(,"att1")
    #[1] "b"
    #attr(,"att2")
    #[1] "2"
    

    选项#2:使用sapply

    my_list[sapply(my_list, function(x)attr(x, "att1") == "b" & attr(x, "att2") == "2")]
    # [[1]]
    # [1] 11 12 13 14 15 16 17 18 19 20
    # attr(,"att1")
    # [1] "b"
    # attr(,"att2")
    # [1] "2"
    

    【讨论】:

    • 不知道为什么这会被否决。似乎很好地说明了如何为此使用 purrr(我不知道如何)。
    • 谢谢@Frank!这对我来说也很奇怪。考虑到您的提示后,我想完成各种选项。但惊讶地投了反对票,这促使我重新检查答案。可能是一些随机用户:-)
    • 我投了赞成票!我对 purrr 不太熟悉,所以我认为这非常有用!
    【解决方案3】:

    可能是这样的:

    ls_attr <- sapply(my_list, attributes)
    ls_attr
    #     [,1] [,2] [,3]
    # att1 "a"  "b"  "c" 
    # att2 "1"  "2"  "3"
    
    my_list[ apply(ls_attr, 2, function(x) all( x %in% c('b', '2') )) ]
    # [[1]]
    # [1] 11 12 13 14 15 16 17 18 19 20
    # attr(,"att1")
    # [1] "b"
    # attr(,"att2")
    # [1] "2"
    

    具有多个属性的另一种解决方案:此代码对属性顺序没有限制。

    ls_attr <- sapply(my_list, attributes)
    search_attr <- matrix( c( 'c', 'b', 2:3), ncol = nrow(ls_attr), byrow = TRUE )
    my_list [ apply( matrix( ls_attr %in% search_attr, nrow = nrow(ls_attr), byrow = FALSE ), 2, all) ]
    

    【讨论】:

    • 为什么不只是 my_list[colSums(ls_attr == "b" | ls_attr == "2") == 2] 而不是 apply 循环?
    • @RichScriven 感谢您的评论。有很多方法可以接近它。我尝试不循环遍历列表,而是先提取属性,最后使用数据(my_list)提取内容
    猜你喜欢
    • 2017-07-18
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2022-08-13
    • 2015-10-08
    • 2011-10-31
    • 2014-07-31
    • 2019-08-26
    相关资源
    最近更新 更多