2.4 列表 (list)
R中的列表是一种特殊的数据存储形式。使用list()
函数来创建列表,比如list(1, 2, 3)
.
data | is.vector() |
is.list() |
is.atomic() |
is.recursive() |
---|---|---|---|---|
list(1, 2, 3) |
TRUE |
TRUE |
FALSE |
TRUE |
c(1 ,2 , 3) |
TRUE |
FALSE |
TRUE |
FALSE |
尝试对列表和向量使用is.vector()
, is.list()
, is.atomic()
和is.recursive()
函数,你会发现列表虽然也是“vector”,但我们一般说的“vector”都是指只能存储一种数据类型的atomic vector;而lists是recursive vector.
这意味着一个list能存储多种类型的数据,且可以包含子列表。列表中的每个分量可以是任何R中的对象 (object):除了常用的 (atomic) vector和另外一个(子)列表以外,还可以有dataframe/tibble和函数:
y <- list(1, c("a","あ"), list(1+3i, c(FALSE, NA, TRUE)),
data.frame(x = c("阿拉木图", "什切青"), y = c(2, 3)),
t.test)
y
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] "a" "あ"
#>
#> [[3]]
#> [[3]][[1]]
#> [1] 1+3i
#>
#> [[3]][[2]]
#> [1] FALSE NA TRUE
#>
#>
#> [[4]]
#> x y
#> 1 阿拉木图 2
#> 2 什切青 3
#>
#> [[5]]
#> function (x, ...)
#> UseMethod("t.test")
#> <bytecode: 0x7fae43b99318>
#> <environment: namespace:stats>
这个列表有5个分量,其中第3个是一个有2个分量的子列表。
2.4.1 列表的索引/取子集
使用上面的例子:
y[2] # 使用单方括号,得到的是一个只有一个分量的列表
#> [[1]]
#> [1] "a" "あ"
y[[2]] # 使用双方括号,得到的是一个向量
#> [1] "a" "あ"
y[[3]][[2]] # 得到的也是一个向量;父列表的索引在前,子列表的在后
#> [1] FALSE NA TRUE
y[[3]] # 这个位置包含两个子列表,因此得到一个有两个分量的列表
#> [[1]]
#> [1] 1+3i
#>
#> [[2]]
#> [1] FALSE NA TRUE
y[[3]][[2]][2] # 得到向量时,直接在后面用单方括号
#> [1] NA
列表里的分量可以有名字;被命名的元素可以通过$
符号抓取:
z <- list(c(1, 3), z2 = c(4, 5, 6), c("a", "b"))
z # `[[2]]`被`$z2`所取代
#> [[1]]
#> [1] 1 3
#>
#> $z2
#> [1] 4 5 6
#>
#> [[3]]
#> [1] "a" "b"
z$z2 == z[[2]] # `z[[2]]`仍然是可用的,结果和`z$z2`一样
#> [1] TRUE TRUE TRUE
2.4.2 合并与拆解
通过c()
函数来合并多个列表。
c(list(1, 2), list(3, 4, list(5,6)))
# 将等同于list(1, 2, 3, 4, list(5,6))
也许你想把需要“合并”的列表作为子列表放在另一个列表里;这也很简单,在本节一开始就讲了:
list(list(1, 2), list(3, 4))
#> [[1]]
#> [[1]][[1]]
#> [1] 1
#>
#> [[1]][[2]]
#> [1] 2
#>
#>
#> [[2]]
#> [[2]][[1]]
#> [1] 3
#>
#> [[2]][[2]]
#> [1] 4
通过unlist()
函数来拆解列表中的子列表。若参数recursive
为TRUE
(默认值),将一直拆解至无子列表的列表,如果此最简列表的所有分量都属于五种atomic vector中的数据20,此列表还会被进一步化简成向量。若recursive = FALSE
,最“靠外”的一级列表(可能是多个)将会被拆解。
unlist(list(1, list(2, list(3, 4)), list(5, 6), 7, 8, 9))
# 将等同于c(1, 2, 3, 4, 5, 6, 7, 8, 9)
# 注意被化简成了向量
unlist(list(1, list(2, list("a", 4)), list(5, TRUE), 7L, 8, 9+0i))
# 将等同于c("1", "2", "a", 4, 5, "TRUE", "7", 8, "9+0i")
# 化简成向量时,非字符元素被强制转换成字符了
unlist(list(1, list(2, list(t.test, 4)), list(5, TRUE), 7L, x, 9+0i))
# t.test无法存储于向量中,因此最简结果为一个list:
# list(1, 2, t.test, 4, 5, TRUE, 7L, x, 9+0i)
unlist(list(1, list(2, 3, list(4, 5)), list(6, 7), 8, 9), recursive = FALSE)
# 将等同于list(1, 2, 3, list(4, 5), 6, 7, 8, 9)
因此,当A
, B
为列表,unlist(list(A, B), recursive = FALSE)
等同于c(A, B)
.
2.4.3 其他性质和操作
上面说到unlist(list(A, B), recursive = FALSE)
等同于c(A, B)
,你可能很想用==
验证一下。很不幸,你会得到一条错误信息:
comparison of these types is not implemented
在第2.6.2节讲过,==
只能用于atomic vectors;对于列表(和其他对象)可以用identical()
函数确认两者是否完全一致。
A <- list("a", 1, TRUE); B <- list(5+8i, NA, 4L)
C1 <- unlist(list(A, B), recursive = FALSE); C2 <- c(A, B)
identical(C1, C2)
#> [1] TRUE
dataframe也是可以unlist成向量的,但是并不实用。(试试
unlist(list(data.frame(x = c(1,2), y = c(3,4)), 5, 6))
)↩