简要背景:许多(大多数?)当代广泛使用的编程语言至少有一些共同的adt[抽象数据类型],特别是,

字符串(由字符组成的序列) List(值的有序集合)和 基于映射的类型(将键映射到值的无序数组)

在R编程语言中,前两者分别实现为字符和向量。

当我开始学习R时,有两件事几乎从一开始就很明显:list是R中最重要的数据类型(因为它是R data.frame的父类),其次,我就是不理解它们是如何工作的,至少在我的代码中不能正确地使用它们。

首先,在我看来,R的列表数据类型是映射ADT的直接实现(Python中的字典,Objective C中的NSMutableDictionary, Perl和Ruby中的散列,Javascript中的对象文字,等等)。

例如,创建它们就像创建Python字典一样,通过将键值对传递给构造函数(在Python中是dict而不是list):

x = list("ev1"=10, "ev2"=15, "rv"="Group 1")

访问R List中的项就像访问Python字典中的项一样,例如x['ev1']。同样,你可以通过以下方法检索“键”或“值”:

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列表也不同于其他地图类型的adt(从我学过的语言中)。我猜这是S的初始规范的结果,也就是说,打算从头开始设计一种数据/统计DSL[领域特定语言]。

R列表与其他广泛使用的语言中的映射类型之间的三个显著区别(例如:Python, Perl, JavaScript):

首先,R中的列表是一个有序的集合,就像向量一样,即使值是键(即键可以是任何可哈希的值,而不仅仅是连续的整数)。其他语言中的映射数据类型几乎总是无序的。

其次,即使在调用函数时没有传入列表,即使返回列表的函数不包含(显式)列表构造函数,也可以从函数返回列表(当然,在实践中可以通过调用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列表的第三个特殊特性:它们似乎不能成为另一个ADT的成员,如果您尝试这样做,那么主容器将被强制转换为列表。例如,

x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)

class(x)
# [1] list

我在这里的意图不是批评这种语言或它是如何被记录的;同样,我并不是说列表数据结构或它的行为有任何问题。我所追求的是纠正我对它们如何工作的理解,这样我就可以在我的代码中正确地使用它们。

以下是我想更好地理解的事情:

What are the rules which determine when a function call will return a list (e.g., strsplit expression recited above)? If I don't explicitly assign names to a list (e.g., list(10,20,30,40)) are the default names just sequential integers beginning with 1? (I assume, but I am far from certain that the answer is yes, otherwise we wouldn't be able to coerce this type of list to a vector w/ a call to unlist.) Why do these two different operators, [], and [[]], return the same result? x = list(1, 2, 3, 4) both expressions return "1": x[1] x[[1]] why do these two expressions not return the same result? x = list(1, 2, 3, 4) x2 = list(1:4)

请不要给我指R文档(?我已经仔细阅读了它,它并不能帮助我回答我刚才背诵的那种问题。

(最后,我最近学习并开始使用一个名为hash的R包(在CRAN上可用),它通过S4类实现了传统的映射类型行为;我当然可以推荐这套套餐。)


当前回答

x = list(1, 2, 3, 4)
x2 = list(1:4)
all.equal(x,x2)

不一样,因为1:4等于c(1,2,3,4) 如果你想让它们相同,那么:

x = list(c(1,2,3,4))
x2 = list(1:4)
all.equal(x,x2)

其他回答

就拿你们的一部分问题来说

这篇关于索引的文章解决了[]和[[]]之间的区别问题。

简而言之,[[]]从列表中选择单个项目,[]返回所选项目的列表。在你的例子中,x = list(1,2,3,4)'项目1是一个整数,但x[[1]]返回一个1,而x[1]返回一个只有一个值的列表。

> x = list(1, 2, 3, 4)
> x[1]
[[1]]
[1] 1

> x[[1]]
[1] 1

关于大家提出的问题,我愿按顺序回答并举例说明:

1)如果return语句添加了一个列表,则返回一个列表。考虑

 R> retList <- function() return(list(1,2,3,4)); class(retList())
 [1] "list"
 R> notList <- function() return(c(1,2,3,4)); class(notList())
 [1] "numeric"
 R> 

2)没有设置名称:

R> retList <- function() return(list(1,2,3,4)); names(retList())
NULL
R> 

3)它们不会返回相同的东西。你的例子给出了

R> x <- list(1,2,3,4)
R> x[1]
[[1]]
[1] 1
R> x[[1]]
[1] 1

其中x[1]返回x的第一个元素——这和x是一样的。每个标量都是长度为1的向量。另一方面,x[[1]]返回列表的第一个元素。

4)最后,两者的不同之处在于,它们分别创建一个包含四个标量的列表和一个包含单个元素的列表(恰好是一个包含四个元素的向量)。

你说:

另一方面,可以返回列表 从函数中 调用时传入一个List 函数,即使函数 不包含List构造函数, 例如,

x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x)
# => 'list'

我猜你认为这是个问题(?)我在这里告诉你为什么这不是问题:-)。您的示例有点简单,因为当您执行字符串拆分时,您拥有一个包含1个元素的列表,因此您知道x[[1]]与unlist(x)[1]相同。但是如果strsplit的结果在每个bin中返回不同长度的结果呢?简单地返回一个向量(而不是一个列表)根本不行。

例如:

stuff <- c("You, me, and dupree",  "You me, and dupree",
           "He ran away, but not very far, and not very fast")
x <- strsplit(stuff, ",")
xx <- unlist(strsplit(stuff, ","))

在第一种情况下(x:返回一个列表),您可以告诉第三个字符串的第二个“部分”是什么,例如:x[[3]][2]。既然结果已经“解开”(未列出),您如何使用xx做同样的事情呢?

再补充一点:

R在散列包中确实有一个与Python dict等效的数据结构。你可以在这篇来自开放数据组的博客文章中读到它。这里有一个简单的例子:

> library(hash)
> h <- hash( keys=c('foo','bar','baz'), values=1:3 )
> h[c('foo','bar')]
<hash> containing 2 key-value pairs.
  bar : 2
  foo : 1

就可用性而言,哈希类非常类似于列表。但对于大型数据集,性能更好。

虽然这是一个相当老的问题,但我必须说,它正好触及了我在R的第一步中所缺失的知识——即如何将我手中的数据表示为R中的对象,或者如何从现有的对象中进行选择。对于一个R新手来说,从一开始就“在R盒子里”思考并不容易。

所以我自己开始使用下面的拐杖,这帮助我找到什么对象使用什么数据,基本上想象现实世界的用法。

虽然我没有给出问题的确切答案,但下面的简短文本可能会帮助那些刚刚以R开头并提出类似问题的读者。

Atomic vector ... I called that "sequence" for myself, no direction, just sequence of same types. [ subsets. Vector ... the sequence with one direction from 2D, [ subsets. Matrix ... bunch of vectors with the same length forming rows or columns, [ subsets by rows and columns, or by sequence. Arrays ... layered matrices forming 3D Dataframe ... a 2D table like in excel, where I can sort, add or remove rows or columns or make arit. operations with them, only after some time I truly recognized that data frame is a clever implementation of list where I can subset using [ by rows and columns, but even using [[. List ... to help myself I thought about the list as of tree structure where [i] selects and returns whole branches and [[i]] returns item from the branch. And because it is tree like structure, you can even use an index sequence to address every single leaf on a very complex list using its [[index_vector]]. Lists can be simple or very complex and can mix together various types of objects into one.

所以对于列表,你可以根据情况选择更多的方法,就像下面的例子。

l <- list("aaa",5,list(1:3),LETTERS[1:4],matrix(1:9,3,3))
l[[c(5,4)]] # selects 4 from matrix using [[index_vector]] in list
l[[5]][4] # selects 4 from matrix using sequential index in matrix
l[[5]][1,2] # selects 4 from matrix using row and column in matrix

这种思维方式对我帮助很大。