访问列表或数据框的元素时,使用方括号 [ ] 和双方括号 [[ ]] 的区别。
访问列表或数据框的元素时,使用方括号 [ ] 和双方括号 [[ ]] 的区别。
R提供了两种不同的方法来访问列表或数据框的元素:[]
和[[]]
。
它们之间的区别是什么,我应该在什么情况下使用其中一种?
这两种方法的显著区别在于它们在提取时返回的对象类别,以及它们在赋值期间是否可以接受一系列值或仅接受单个值。
考虑以下列表的数据提取情况:
foo <- list( str='R', vec=c(1,2,3), bool=TRUE )
假设我们想要从 foo 中提取 bool 存储的值,并在 if()
语句中使用它。这将说明使用 []
和 [[]]
进行数据提取时返回值之间的差异。使用 []
方法将返回 class list 的对象(如果 foo 是 data.frame,则为 class data.frame),而 [[]]
方法将返回其 class 受其值类型的影响的对象。
因此,使用 []
方法会得到以下结果:
if( foo[ 'bool' ] ){ print("Hi!") } Error in if (foo["bool"]) { : argument is not interpretable as logical class( foo[ 'bool' ] ) [1] "list"
这是因为 []
方法返回了一个列表,而列表不能直接传递给 if()
语句。在这种情况下,我们需要使用 [[]]
,因为它将返回存储在 'bool' 中的“裸”对象,它将具有适当的 class:
if( foo[[ 'bool' ]] ){ print("Hi!") } [1] "Hi!" class( foo[[ 'bool' ]] ) [1] "logical"
第二个区别在于,[]
运算符可以用于访问列表中的一系列插槽或数据框中的列,而 [[]]
运算符仅限于访问单个插槽或列。考虑使用第二个列表 bar()
进行值分配的情况:
bar <- list( mat=matrix(0,nrow=2,ncol=2), rand=rnorm(1) )
假设我们想要用 bar 中的数据覆盖 foo 的最后两个插槽。如果我们尝试使用 [[]]
运算符,会发生以下情况:
foo[[ 2:3 ]] <- bar Error in foo[[2:3]] <- bar : more elements supplied than there are to replace
这是因为[[]]
只能访问单个元素。我们需要使用[]
:
foo[ 2:3 ] <- bar print( foo ) $str [1] "R" $vec [,1] [,2] [1,] 0 0 [2,] 0 0 $bool [1] -0.6291121
请注意,尽管赋值成功了,但是foo
中的插槽仍然保留其原始名称。
R 语言定义很方便回答这些类型的问题:
R 有三个基本的索引操作符,语法如下所示:
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"对于向量和矩阵,
[[
形式很少使用,尽管它们与[
形式有一些轻微的语义差异(例如,它会删除任何名称或 dimnames 属性,并且使用字符索引来进行部分匹配)。当使用单个索引索引多维结构时,x[[i]]
或x[i]
将返回x
的第 i 个连续元素。对于列表,一般使用
[[
来选择任意单个元素,而[
返回所选元素的列表。
[[
形式只允许使用整数或字符索引选择单个元素,而[
允许通过向量进行索引。但请注意,对于列表,索引可能是一个向量,并且该向量的每个元素依次应用于列表、所选组件、该组件的所选部分等。结果仍然是一个单一的元素。