【问题标题】:R - Multi-level list indexingR - 多级列表索引
【发布时间】:2020-08-27 02:33:59
【问题描述】:

将对象分配给多级列表的约定是什么?

到目前为止,我认为索引的约定1,2 是使用[[]] 而不是$

因此,在循环中保存结果时,我通常使用以下方法:

> result <- matrix(2,2,2)

> result_list <- list()
> result_list[["A"]][["B"]][["C"]] <- result
> print(result_list)
$A
$A$B
$A$B$C
     [,1] [,2]
[1,]    2    2
[2,]    2    2

这与该矩阵的预期一致。 但是当分配一个数字时,列表似乎跳过了最后一级。

> result <- 2
> result_list <- list()
> result_list[["A"]][["B"]][["C"]] <- result
> print(result_list)
$A
B 
2 

同时,如果我使用$ 而不是[[]],则该列表再次作为意图。

> result_list$A$B$C <- result
> print(result_list)
$A
$A$B
$A$B$C
[1] 2

正如提到的here,您也可以使用list("A" = list("B" = list("C" = 2)))

哪些方法应该用于在 R 中为多级列表建立索引?

【问题讨论】:

  • 我无法确认此行为。我总是得到相同的列表结构。你用的是什么版本(4.0.0)?
  • 可以在 3.6.2 版本上确认此异常。但是我不知道为什么会这样
  • 我使用的是 3.6.3 版
  • 我猜这种行为可能与recent change in R-4.0.0 相关联,关于将length == 1 向量分配给NULL 列表元素(这里是您的result_list[["A"]])的行为。

标签: r list


【解决方案1】:

虽然问题的标题是指多级列表索引,并且mylist[['a']][['b']][['c']]的语法与检索多级列表元素的语法相同,但区别在于您所观察到的实际上来自对多级列表的 creation (或不)使用相同的语法。

为了展示这一点,我们可以首先显式创建多级(嵌套)列表,然后检查矩阵和单个数字的索引是否按预期工作。

mymatrix=matrix(1:4,nrow=2)
list_b=list(c=mymatrix)
list_a=list(b=list_b)
mynestedlist1=list(a=list_a)
str( mynestedlist1 )
# List of 1
#  $ a:List of 1
#   ..$ b:List of 1
#   .. ..$ c: int [1:2, 1:2] 1 2 3 4

mynumber=2
list_e=list(f=mynumber)
list_d=list(e=list_e)
mynestedlist2=list(d=list_d)
str( mynestedlist2 )
# List of 1
#  $ d:List of 1
#   ..$ e:List of 1
#   .. ..$ f: num 2

(请注意,为了清楚起见,我已经按顺序创建了列表;这些列表可以全部放在一行中,例如:mynestedlist2=list(d=list(e=list(f=mynumber)))

无论如何,现在我们将检查索引是否正常:

str(mynestedlist1[['a']][['b']][['c']])
# int [1:2, 1:2] 1 2 3 4
str(mynestedlist1$a$b$c)
# int [1:2, 1:2] 1 2 3 4

str(mynestedlist2[['d']][['e']][['f']])
# num 2
str(mynestedlist2$d$e$f)
# num 2

# and, just to check that we don't 'skip the last level':
str(mynestedlist2[['d']][['e']])
# List of 1
#  $ f: num 2

因此,对于“应该使用这些方法中的哪一个来索引 R 中的多级列表”这个问题的直接答案是:“它们中的任何一个 - 它们都可以”

那么问题中的示例是怎么回事呢?

这里,相同的语法被用来尝试隐式创建列表,并且由于嵌套列表的结构没有明确指定,这取决于R是否可以推断出你想要的结构.

在第一个和第三个示例中,没有歧义,但每个示例都有不同的原因:

第一个例子:

mynestedlist1=list()
mynestedlist1[['a']][['b']][['c']]=mymatrix

我们已经指定mynestedlist1 是一个列表。但它的元素可以是任何类型的对象,直到我们分配它们。在这种情况下,我们将具有元素'b' 的对象放入名为'a' 的元素中,该对象包含具有元素'c' 的对象,即矩阵。由于除了列表之外没有任何 R 对象可以在单个元素中包含矩阵,因此实现此分配的唯一方法是创建嵌套列表。

第三个例子:

mynestedlist3=list()
mynestedlist3$g$h$i=mynumber

在这种情况下,我们使用了$ 表示法,它仅适用于列表(或与列表相似/等效的数据类型,如数据帧)。所以,再一次,遵循这个赋值指令的唯一方法是创建一个嵌套列表。

最后是讨厌的第二个例子,但从它的一个更简单的变体开始:

mylist2=list()
mylist2[['c']][['d']]=mynumber

这里有一个模棱两可的地方。我们已经指定mylist2 是一个列表,并且我们在名为'c' 的元素中放入了一个对象,该对象的元素'd' 包含一个数字。这个元素可以是一个列表,但也可以是一个简单的向量,在这种情况下,R 选择它作为更简单的选项:

str(mylist2)
# List of 1
#  $ c: Named num 2
#   ..- attr(*, "names")= chr "d"

将此与尝试使用完全相同的语法分配矩阵时的行为进行对比:在这种情况下,遵循语法的唯一方法是在第一个列表中创建另一个嵌套列表。

完整的第二个示例mylist2[['c']][['d']][['e']]=mynumber 怎么样,我们尝试将一个名为'e' 的数字分配给刚刚创建但仍为空的对象'd'
这似乎很不清楚,这可能是不同版本的 R 行为不同的原因(如问题的 cmets 中所报告的)。在问题中,R 采取的行动是在删除其名称的同时分配数字,类似于:

myvec=vector(); myvec2=vector()
myvec[['a']]=1
myvec2[['b']]=2
myvec[['a']]=myvec2
str(myvec)
#  Named num 2
#  - attr(*, "names")= chr "a"

然而,语法本身似乎并不强制这种行为,因此在尝试创建嵌套列表或向量列表时避免依赖这种行为是明智的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-26
    • 2020-08-20
    • 1970-01-01
    • 2018-06-24
    • 1970-01-01
    • 2016-12-08
    • 2023-03-23
    • 2019-12-30
    相关资源
    最近更新 更多