【问题标题】:What is the difference between a list and a pairlist in R?R中的列表和配对列表有什么区别?
【发布时间】:2015-06-07 15:43:11
【问题描述】:

在阅读列表文档时,我发现了对配对列表的引用,但我不清楚它们与列表有何不同。

【问题讨论】:

    标签: r list


    【解决方案1】:

    R 中的配对名单

    在日常 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
    

    【讨论】:

      【解决方案2】:

      首先,pairlists 已被弃用

      pairlistsdeprecated 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?


      pairlists 可以包含 empty 命名元素

      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()可能会更好
      • 我认为它可能被称为pairlist,因为大小限制(三个元素),对于您拥有的语言对象和运算符元素(第一个),然后是一对参数(第二个,第三个参数)。
      • 我投了反对票,请提供为什么不推荐配对列表的参考,然后我会把它变成赞成票。我在手册中没有找到任何信息。对于高度嵌套的结构或对语言对象进行操作的元编程来说,它似乎仍然合理。
      • @jangorecki 我添加了您请求的链接。
      猜你喜欢
      • 2013-03-31
      • 2013-04-03
      • 2010-11-05
      • 2010-10-12
      • 2012-12-09
      相关资源
      最近更新 更多