虽然问题的标题是指多级列表索引,并且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"
然而,语法本身似乎并不强制这种行为,因此在尝试创建嵌套列表或向量列表时避免依赖这种行为是明智的。