【发布时间】:2015-06-07 15:43:11
【问题描述】:
在阅读列表文档时,我发现了对配对列表的引用,但我不清楚它们与列表有何不同。
【问题讨论】:
在阅读列表文档时,我发现了对配对列表的引用,但我不清楚它们与列表有何不同。
【问题讨论】:
在日常 R 中,配对列表通常会出现在两个地方。一个是作为函数形式:
str(formals(var))
另一个是作为语言对象。例如:
quote(1 + 1)
产生一个类型语言的配对列表(LANGSXP 内部)。您甚至会关心意识到这一点的主要原因是,诸如 length(<language object>) 或 language_object[[x]] 之类的操作可能会很慢,因为pairlist 是如何在内部存储的(尽管长的pairlist 语言对象很少见;注意表达式不是pairlists )。
请注意,空元素只是长度为零的符号,如果您稍微作弊,您实际上可以将它们存储在列表中(尽管您可能不应该这样做):
list(x=substitute(x, alist(x=))) # hack alert
话虽如此,在大多数情况下,OP 是正确的,除非您正在编写用于 R 的 C 代码,否则您无需过多担心配对列表。
Pairlists 和 list 的不同之处主要在于它们的存储结构。对列表存储为节点链,其中每个节点都指向下一个节点的位置以及节点的内容和节点的“名称”(参见 CAR/CDR wiki article for generic discussion)。这意味着除非您知道第一个元素是哪个元素,否则您无法知道配对列表中有多少元素,然后遍历整个列表。
Pairlists 在 R 内部被广泛使用,并且在正常的 R 使用中确实存在,但大多数时候被 print 或 access 方法伪装和/或在访问时强制为列表。
列表也是地址列表,但与对列表不同,所有地址都存储在一个连续的内存位置并跟踪总长度。这使得按位置访问列表的任意成员变得容易,因为您只需在内存表中查找地址即可。使用pairlist,您必须从一个节点跳到另一个节点,直到最终到达所需的节点。名称也存储为列表的属性,而不是附加到对列表的每个节点上。
pairlists 的一个(通常很小的)好处是您可以以最小的开销添加到它们,因为您最多只需要修改两个节点(新节点之前的节点和新节点本身),而使用列表您可能需要重新分配整个地址表并增加大小(这通常不是什么大问题,因为地址表与表指向的数据大小相比通常非常小)。还有许多专门用于对列表操作的算法(例如排序、索引等),但这些也可以移植到普通列表。
与日常使用不太相关,因为您只能在内部执行此操作,从编程角度通过更改任意元素指向的内容来修改列表非常容易。
与上述内容松散相关,当您拥有高度嵌套的对象时,配对列表可能会更有效。列表可以很容易地复制这种结构,但是每个列表和嵌套列表都会背负额外的内存地址表。这可能是对很可能具有高嵌套/元素比率的语言对象使用配对列表的原因。
有关详细信息,请参阅 R Internals(在链接位置分别查找 LISTSXP 和 VECSXP、配对列表和列表)。
编辑: 有趣的是,将列表的内存占用与配对列表进行比较的实验显示配对列表更大,因此存储效率参数可能不正确(不确定 object.size 是否可以在这里信任):
> plist_to_list <- function(x) {
+ if(is.call(x)) x <- as.list(x)
+ if(length(x) > 1) for(i in 2:length(x)) x[[i]] <- Recall(x[[i]])
+ x
+ }
> add_quote <- function(x, y) call("+", x, y)
> x <- Reduce(add_quote, lapply(letters, as.name))
> object.size(x)
7056 bytes
> y <- plist_to_list(x)
> object.size(y)
4656 bytes
【讨论】:
pairlists 是deprecated for normal use,因为“通用向量”通常更有效。除非您正在研究 R 内部,否则您永远不需要担心它们。
R 中列表中的每个元素都可以有一个名称。您可以通过名称或数字索引访问列表中的每个元素。
这是一个列表示例,其中第二个元素被命名为“第二个”:
> my.list <- list('A',second='B','C')
> my.list
[[1]]
[1] "A"
$second
[1] "B"
[[3]]
[1] "C"
所有元素都可以通过它在列表中的位置来索引。命名元素还可以通过名称访问:
> my.list[[2]]
[1] "B"
> my.list$second
[1] "B"
此外,列表中的每个元素都是一个向量,即使它只是一个包含单个元素的向量。有关列表的更多信息,请参阅How to Correctly Use Lists in R?。
pairlist 与 list 基本相同,只是 pairlist 可以包含一个空的命名元素,但 list 不能。此外,还使用alist 函数构造了一个配对列表。
> list('A',second=,'C')
Error in as.pairlist(list(...)) : argument is missing, with no default
> alist('A',second=,'C')
[[1]]
[1] "A"
$second
[[3]]
[1] "C"
但是,如前所述,它们已被弃用。与我所知道的列表相比,它们没有任何好处或优势。
【讨论】:
bquote() 作为元素。对于为未指定维数的数组编写函数,使用do.call("[", c(list(arr), ...)) 非常有用,您可能希望参数列表包含bquote()。我想bquote() 基本上允许list 做所有alist 可以做的事情。知道为什么将配对列表称为配对列表吗?
bquote(),使用substitute()可能会更好