R提供了两种不同的方法来访问list或data.frame中的元素:[]和[[]]。

这两者之间的区别是什么,什么时候我应该使用其中一个而不是另一个?


当前回答

它们都是子集的方法。 单括号将返回列表的一个子集,该子集本身就是一个列表。也就是说,它可能包含也可能不包含一个以上的元素。 另一方面,双括号将只返回列表中的单个元素。

-单括号会给出一个列表。如果希望从列表中返回多个元素,也可以使用单个括号。 考虑以下列表:

>r<-list(c(1:10),foo=1,far=2);

现在,请注意当我试图显示列表时返回的方式。 我输入r并按enter。

>r

#the result is:-

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

$foo

[1] 1

$far

[1] 2

现在我们来看看单括号的神奇之处:

>r[c(1,2,3)]

#the above command will return a list with all three elements of the actual list r as below

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

$foo

[1] 1


$far

[1] 2

这与我们试图在屏幕上显示r值时完全相同,这意味着使用单括号返回了一个列表,其中在索引1处我们有一个包含10个元素的向量,然后我们有两个名称为foo和far的元素。 我们也可以选择一个索引或元素名作为单个括号的输入。 例如,:

> r[1]

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

在这个例子中,我们给出了一个索引“1”,作为回报,我们得到了一个包含一个元素的列表(它是一个包含10个数字的数组)

> r[2]

$foo

[1] 1

在上面的例子中,我们给出了一个索引“2”,作为回报,我们得到了一个包含一个元素的列表:

> r["foo"];

$foo

[1] 1

在本例中,我们传递一个元素的名称,返回一个包含一个元素的列表。

你也可以传递一个包含元素名称的向量,比如:

> x<-c("foo","far")

> r[x];

$foo

[1] 1

$far
[1] 2

在这个例子中,我们传递了一个有两个元素名为“foo”和“far”的向量。

作为回报,我们得到了一个包含两个元素的列表。

简而言之,单个括号将总是返回另一个列表,其中元素的数量等于传递到单个括号中的元素的数量或索引的数量。

相反,双括号总是只返回一个元素。 在转到双括号之前,要记住一点。 注意:两者之间的主要区别是,单括号将返回包含任意数量元素的列表,而双括号将永远不会返回列表。相反,双括号只返回列表中的单个元素。

我将举几个例子。请记下加粗的单词,在你完成下面的例子后再回头看:

双括号将返回索引处的实际值。(它不会返回一个列表)

  > r[[1]]

     [1]  1  2  3  4  5  6  7  8  9 10


  >r[["foo"]]

    [1] 1

对于双括号,如果我们试图通过传递一个向量来查看多个元素,就会导致错误,因为它不是为了满足这个需要而构建的,而是为了返回单个元素。

考虑以下几点

> r[[c(1:3)]]
Error in r[[c(1:3)]] : recursive indexing failed at level 2
> r[[c(1,2,3)]]
Error in r[[c(1, 2, 3)]] : recursive indexing failed at level 2
> r[[c("foo","far")]]
Error in r[[c("foo", "far")]] : subscript out of bounds

其他回答

R语言定义对于回答这些类型的问题很方便:

http://cran.r-project.org/doc/manuals/R-lang.html#Indexing

R has three basic indexing operators, with syntax displayed by the following examples x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a" For vectors and matrices the [[ forms are rarely used, although they have some slight semantic differences from the [ form (e.g. it drops any names or dimnames attribute, and that partial matching is used for character indices). When indexing multi-dimensional structures with a single index, x[[i]] or x[i] will return the ith sequential element of x. For lists, one generally uses [[ to select any single element, whereas [ returns a list of the selected elements. The [[ form allows only a single element to be selected using integer or character indices, whereas [ allows indexing by vectors. Note though that for a list, the index can be a vector and each element of the vector is applied in turn to the list, the selected component, the selected component of that component, and so on. The result is still a single element.

双括号访问列表元素,而单括号返回一个包含单个元素的列表。

lst <- list('one','two','three')

a <- lst[1]
class(a)
## returns "list"

a <- lst[[1]]
class(a)
## returns "character"

对于另一个具体的用例,当您想要选择split()函数创建的数据帧时,使用双括号。如果您不知道,split()会根据关键字段将列表/数据帧分组为子集。如果你想对多个组进行操作,绘制它们,等等,这很有用。

> class(data)
[1] "data.frame"

> dsplit<-split(data, data$id)
> class(dsplit)
[1] "list"

> class(dsplit['ID-1'])
[1] "list"

> class(dsplit[['ID-1']])
[1] "data.frame"

它们都是子集的方法。 单括号将返回列表的一个子集,该子集本身就是一个列表。也就是说,它可能包含也可能不包含一个以上的元素。 另一方面,双括号将只返回列表中的单个元素。

-单括号会给出一个列表。如果希望从列表中返回多个元素,也可以使用单个括号。 考虑以下列表:

>r<-list(c(1:10),foo=1,far=2);

现在,请注意当我试图显示列表时返回的方式。 我输入r并按enter。

>r

#the result is:-

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

$foo

[1] 1

$far

[1] 2

现在我们来看看单括号的神奇之处:

>r[c(1,2,3)]

#the above command will return a list with all three elements of the actual list r as below

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

$foo

[1] 1


$far

[1] 2

这与我们试图在屏幕上显示r值时完全相同,这意味着使用单括号返回了一个列表,其中在索引1处我们有一个包含10个元素的向量,然后我们有两个名称为foo和far的元素。 我们也可以选择一个索引或元素名作为单个括号的输入。 例如,:

> r[1]

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

在这个例子中,我们给出了一个索引“1”,作为回报,我们得到了一个包含一个元素的列表(它是一个包含10个数字的数组)

> r[2]

$foo

[1] 1

在上面的例子中,我们给出了一个索引“2”,作为回报,我们得到了一个包含一个元素的列表:

> r["foo"];

$foo

[1] 1

在本例中,我们传递一个元素的名称,返回一个包含一个元素的列表。

你也可以传递一个包含元素名称的向量,比如:

> x<-c("foo","far")

> r[x];

$foo

[1] 1

$far
[1] 2

在这个例子中,我们传递了一个有两个元素名为“foo”和“far”的向量。

作为回报,我们得到了一个包含两个元素的列表。

简而言之,单个括号将总是返回另一个列表,其中元素的数量等于传递到单个括号中的元素的数量或索引的数量。

相反,双括号总是只返回一个元素。 在转到双括号之前,要记住一点。 注意:两者之间的主要区别是,单括号将返回包含任意数量元素的列表,而双括号将永远不会返回列表。相反,双括号只返回列表中的单个元素。

我将举几个例子。请记下加粗的单词,在你完成下面的例子后再回头看:

双括号将返回索引处的实际值。(它不会返回一个列表)

  > r[[1]]

     [1]  1  2  3  4  5  6  7  8  9 10


  >r[["foo"]]

    [1] 1

对于双括号,如果我们试图通过传递一个向量来查看多个元素,就会导致错误,因为它不是为了满足这个需要而构建的,而是为了返回单个元素。

考虑以下几点

> r[[c(1:3)]]
Error in r[[c(1:3)]] : recursive indexing failed at level 2
> r[[c(1,2,3)]]
Error in r[[c(1, 2, 3)]] : recursive indexing failed at level 2
> r[[c("foo","far")]]
Error in r[[c("foo", "far")]] : subscript out of bounds

只是在这里添加[[也用于递归索引。

@JijoMatthew在回答中暗示了这一点,但没有深入探讨。

正如在?"[["中所指出的,像x[[y]]这样的语法,其中长度(y) > 1被解释为:

x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]

注意,这并没有改变关于[和[[]之间的主要区别,即前者用于子集设置,后者用于提取单个列表元素。

例如,

x <- list(list(list(1), 2), list(list(list(3), 4), 5), 6)
x
# [[1]]
# [[1]][[1]]
# [[1]][[1]][[1]]
# [1] 1
#
# [[1]][[2]]
# [1] 2
#
# [[2]]
# [[2]][[1]]
# [[2]][[1]][[1]]
# [[2]][[1]][[1]][[1]]
# [1] 3
#
# [[2]][[1]][[2]]
# [1] 4
#
# [[2]][[2]]
# [1] 5
#
# [[3]]
# [1] 6

要得到值3,我们可以这样做:

x[[c(2, 1, 1, 1)]]
# [1] 3

回到上面@JijoMatthew的答案,回想一下r:

r <- list(1:10, foo=1, far=2)

特别是,这解释了我们在误用[[时往往会得到的错误,即:

r[[1:3]]

r[[1:3]]中的错误:递归索引在级别2失败

由于这段代码实际上试图求值r[[1]][[2]][[3]],并且r的嵌套在第一级停止,因此通过递归索引提取的尝试在[[2]]失败,即在第2级。

r[[c("foo", "far")]]错误:下标越界

这里,R正在寻找R [["foo"]][["far"]],而R并不存在,所以我们得到了下标越界错误。

如果这两个错误给出相同的信息,可能会更有帮助/一致一些。