- 字符串(由字符组成的序列) - 列表(值的有序集合),以及 - 基于映射的类型(将键映射到值的无序数组)
在R编程语言中,前两者分别实现为
character
和vector
。当我开始学习R时,从一开始就有两件事是显而易见的:列表是R中最重要的数据类型(因为它是R
data.frame
的父类),其次,我就是无法理解它们的工作原理,至少不足以在我的代码中正确使用它们。首先,对我来说,R的
list
数据类型似乎是map ADT(在Python中是dictionary
,在Objective C中是NSMutableDictionary
,在Perl和Ruby中是hash
,在Javascript中是object literal
等)的一个直接实现。例如,您可以像创建Python字典一样通过向构造函数传递键值对来创建它们(在Python中是
dict
而不是list
):x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
您可以像访问Python字典一样访问R List中的项,例如x['ev1']
。同样,您可以通过以下方式仅检索'keys'或仅检索'values':
names(x) # fetch just the 'keys' of an R list
# [1] "ev1" "ev2" "rv"
unlist(x) # fetch just the 'values' of an R list
# ev1 ev2 rv
# "10" "15" "Group 1"
x = list("a"=6, "b"=9, "c"=3)
sum(unlist(x))
# [1] 18
但是,R中的list
也与其他映射类型ADT(至少在我学过的语言中)不同。我的猜测是这是基于S的初始规范的结果,即意图从头开始设计一个数据/统计DSL [特定领域语言]。
R中的list
和其他广泛使用的语言中的映射类型有三个重要差异(例如Python、Perl、JavaScript):
首先,R中的list
是一种有序集合,就像向量一样,即使值是键控的(即,键可以是任何可哈希值,而不仅仅是连续整数)。几乎总是,在其他语言中,映射数据类型是无序的。
其次,list
可以从函数返回,即使在调用函数时你没有传递list
,而且即使返回list
的函数不包含(显式的)list
构造函数(当然,你可以通过将返回结果包装在对unlist
的调用中来处理这个问题):
x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x) # returns 'list', not a vector of length 2
# [1] list
R的list
的第三个特点:它似乎不能成为另一个ADT的成员,如果你尝试这样做,那么主容器将被强制转换为list
。例如:
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
我在这里的意图不是批评语言或者它的文档,同样的,我也不认为list
数据结构或者其行为有任何问题。我只是想纠正对它们如何工作的理解,以便我可以正确地在我的代码中使用它们。
以下是我想更好地了解的内容:
什么规则决定了函数调用何时返回一个
list
(例如,上面提到的strsplit
表达式)?如果我没有显式地为
list
分配名称(例如,list(10,20,30,40)
),默认名称是否只是从 1 开始的顺序整数?(我假设答案是肯定的,否则我们就无法通过调用unlist
将此类型的list
强制转换为向量。)为什么这两个不同的运算符
[]
和[[]]
返回 相同 的结果?x = list(1, 2, 3, 4)
这两个表达式都返回 "1":
x[1]
x[[1]]
为什么这两个表达式不返回相同的结果?
x = list(1, 2, 3, 4)
x2 = list(1:4)
?list
,R-intro
),我已经仔细阅读过它,但它并不能帮助我回答上述问题的类型。(最后,我最近了解并开始使用一个R包(可在CRAN上获得),名为
hash
,它通过S4类实现了传统的映射类型行为;我当然可以推荐这个包。)
x = list(1, 2, 3, 4)
,使用x[1]
和x[[1]]
并不会得到相同的结果。前者返回一个列表,后者返回一个数值向量。向下滚动看来,我认为 Dirk 是唯一一个正确回答这个问题的人。 - IRTFMR
语言中list
与哈希表不同的方法,我还有一个认为值得注意的。在R
中,list
可以有两个具有相同引用名称的成员。考虑到obj <- c(list(a = 1),list(a = 2))
是有效的,并返回一个具有两个名为'a'的命名值的列表。在这种情况下,对于obj["a"]
的调用将仅返回第一个匹配的列表元素。您可以使用R
中的环境来获得类似于哈希表的行为(可能是相同的),每个引用名称只使用一个条目,例如x <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
。 - russellpierce