如何正确使用R中的列表?

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


字符串(由字符组成的序列)


列表(值的有序集合),以及


基于映射的类型(将键映射到值的无序数组)


在R编程语言中,前两个分别作为character和实现vector。


当我开始学习R时,几乎从一开始就显而易见两件事:list是R中最重要的数据类型(因为它是R的父类data.frame),第二,我至少不了解它们的工作方式,至少不够好,无法在我的代码中正确使用它们。


一方面,在我看来,R的list数据类型是对映射ADT的直接实现(dictionary在Python中,NSMutableDictionary在Objective C中,hash在Perl和Ruby中,object literal在Javascript中,等等)。


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


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

然后您就可以像访问Python字典那样访问R列表中的项目,例如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 list也不同于其他映射类型的ADT(无论如何,从我所学的语言中)。我的猜测是,这是S最初规格的结果,即,打算从头开始设计数据/统计DSL(特定领域语言)。


R list和其他广泛使用的语言(例如Python,Perl,JavaScript)的映射类型之间的三个重要区别:


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


第二,listS可从即使你在一个从来没有通过函数返回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的独特功能listS:它似乎并不认为他们可以是另一种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开头的连续整数?(我假设,但是我不确定答案是否定的,否则我们将无法强制将这种类型的list向量强制为w或对的调用unlist。)


为什么这两个不同的运算符,[]和[[]]返回相同的结果?


x = list(1, 2, 3, 4)


这两个表达式都返回“ 1”:


x[1]


x[[1]]


为什么这两个表达式不能返回相同的结果?


x = list(1, 2, 3, 4)


x2 = list(1:4)


请不要将我指向R文档(),我已经仔细阅读了该文档?list,R-intro它不能帮助我回答上面刚刚提到的问题类型。


(最后,我最近了解并开始使用一个R包(在CRAN上可用)hash,该包通过S4类实现常规的映射类型行为;我当然可以推荐此包。)


牛魔王的故事
浏览 709回答 3
3回答

慕田峪7331174

只是为了解决您问题的最后一部分,因为这实际上指出了R list和vectorR 之间的区别:为什么这两个表达式不能返回相同的结果?x = list(1、2、3、4); x2 =列表(1:4)列表可以包含任何其他类作为每个元素。因此,您可以拥有一个列表,其中第一个元素是字符向量,第二个元素是数据帧,等等。在这种情况下,您创建了两个不同的列表。 x有四个向量,每个向量的长度为1。 x2有1个向量的长度为4:> length(x[[1]])[1] 1> length(x2[[1]])[1] 4所以这些是完全不同的列表。R列表非常类似于哈希映射数据结构,因为每个索引值都可以与任何对象关联。这是一个包含3个不同类(包括一个函数)的列表的简单示例:> complicated.list <- list("a"=1:4, "b"=1:3, "c"=matrix(1:4, nrow=2), "d"=search)> lapply(complicated.list, class)$a[1] "integer"$b[1] "integer"$c[1] "matrix"$d[1] "function"鉴于最后一个元素是搜索功能,我可以这样称呼它:> complicated.list[["d"]]()[1] ".GlobalEnv" ...作为对此的最后评论:应该注意,a data.frame实际上是一个列表(来自data.frame文档):数据框是具有给定类'“ data.frame”'的具有相同行名称的具有相同行数的变量的列表因此,a中的列data.frame可以具有不同的数据类型,而矩阵中的列则不能。例如,在这里我尝试创建一个由数字和字符组成的矩阵:> a <- 1:4> class(a)[1] "integer"> b <- c("a","b","c","d")> d <- cbind(a, b)> d&nbsp;a&nbsp; &nbsp;b&nbsp;&nbsp;[1,] "1" "a"[2,] "2" "b"[3,] "3" "c"[4,] "4" "d"> class(d[,1])[1] "character"请注意我如何无法将第一列的数据类型更改为数字,因为第二列具有字符:> d[,1] <- as.numeric(d[,1])> class(d[,1])[1] "character"

湖上湖

关于您的问题,让我依次解决并举例:1)如果return语句添加一个列表,则返回一个列表。考虑&nbsp;R> retList <- function() return(list(1,2,3,4)); class(retList())&nbsp;[1] "list"&nbsp;R> notList <- function() return(c(1,2,3,4)); class(notList())&nbsp;[1] "numeric"&nbsp;R>&nbsp;2)根本没有设置名称:R> retList <- function() return(list(1,2,3,4)); names(retList())NULLR>&nbsp;3)他们不会返回相同的东西。你的例子给出R> x <- list(1,2,3,4)R> x[1][[1]][1] 1R> x[[1]][1] 1其中x[1]返回的第一个元素x-这是一样的x。每个标量都是一个长度为1的向量。另一方面,x[[1]]返回列表的第一个元素。4)最后,两者之间是不同的,它们分别创建了一个包含四个标量的列表和一个包含单个元素的列表(碰巧是四个元素的向量)。分享编辑
打开App,查看更多内容
随时随地看视频慕课网APP