列表(List)是 R 语言中最灵活 的数据结构。与向量不同,列表可以存放不同类型的数据------数值、字符串、向量、甚至其他列表,统统可以放进去。在 R 实际开发中,很多函数的返回值都是列表。
一、为什么需要列表?
回顾一下向量的限制:
r
# 向量只能存同类型,混合类型会自动转换
c(1, "hello", TRUE)
# → "1" "hello" "TRUE" 全变成了字符串!
列表打破了这个限制:
r
list(1, "hello", TRUE, c(1, 2, 3))
# → 数值、字符串、逻辑值、向量,各就各位
二、创建列表
1. 基本创建
r
student <- list(
name = "张三",
age = 20,
scores = c(92, 85, 78),
passed = TRUE
)
print(student)
运行结果:
txt
$name
[1] "张三"
$age
[1] 20
$scores
[1] 92 85 78
$passed
[1] TRUE
2. 不命名也行
r
info <- list("张三", 20, c(92, 85, 78))
print(info)
运行结果:
txt
[[1]]
[1] "张三"
[[2]]
[1] 20
[[3]]
[1] 92 85 78
三、访问列表元素
列表有三种访问方式,必须搞清楚区别:
1. 用 $ 按名称访问(最常用)
r
student <- list(name = "张三", age = 20, scores = c(92, 85, 78))
print(student$name)
print(student$scores)
运行结果:
txt
[1] "张三"
[1] 92 85 78
2. 用 [["名称"]] 访问
r
student <- list(name = "张三", age = 20, scores = c(92, 85, 78))
print(student[["name"]])
print(student[["scores"]])
运行结果:
txt
[1] "张三"
[1] 92 85 78
3. 用 [[索引]] 按位置访问
r
student <- list(name = "张三", age = 20, scores = c(92, 85, 78))
print(student[[1]]) # 第1个元素
print(student[[3]]) # 第3个元素
运行结果:
txt
[1] "张三"
[1] 92 85 78
4. [ ] 和 [[ ]] 的区别(重点!)
r
student <- list(name = "张三", age = 20)
# [[]] 取出的是元素本身
print(class(student[[1]])) # "character"
# [] 取出的是子列表
print(class(student[1])) # "list"
| 方式 | 返回类型 | 用途 |
|---|---|---|
list$name |
元素本身 | 取单个元素 |
list[["name"]] |
元素本身 | 取单个元素 |
list[[1]] |
元素本身 | 按位置取元素 |
list[1] |
子列表 | 取一个子列表 |
list[1:2] |
子列表 | 取多个元素组成的子列表 |
简单记忆:一个括号 [ ] 切片,两个括号 [[ ]] 取值。
四、修改列表元素
r
student <- list(name = "张三", age = 20, scores = c(92, 85, 78))
# 修改元素
student$age <- 21
print(student$age)
# 修改向量中的某个值
student$scores[2] <- 90
print(student$scores)
# 添加新元素
student$gender <- "男"
print(student$gender)
# 删除元素(赋值为 NULL)
student$passed <- TRUE
student$passed <- NULL
print(student)
运行结果:
txt
[1] 21
[1] 92 90 78
[1] "男"
$name
[1] "张三"
$age
[1] 21
$scores
[1] 92 90 78
$gender
[1] "男"
五、列表常用操作
1. 查看列表结构
r
student <- list(name = "张三", age = 20, scores = c(92, 85, 78))
length(student) # 元素个数 → 3
names(student) # 所有元素名 → "name" "age" "scores"
str(student) # 查看结构(调试常用)
str() 输出:
txt
List of 3
$ name : chr "张三"
$ age : num 20
$ scores: num [1:3] 92 85 78
2. 判断是否是列表
r
student <- list(name = "张三")
is.list(student) # TRUE
is.list(c(1, 2, 3)) # FALSE
3. 列表与向量互转
r
# 向量 → 列表
v <- c(1, 2, 3)
lst <- as.list(v)
print(lst)
# 列表 → 向量(扁平化)
lst <- list(a = 1, b = 2, c = 3)
v <- unlist(lst)
print(v)
运行结果:
txt
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
a b c
1 2 3
4. 合并列表
r
part1 <- list(name = "张三", age = 20)
part2 <- list(city = "北京", school = "清华大学")
full <- c(part1, part2)
print(full)
运行结果:
txt
$name
[1] "张三"
$age
[1] 20
$city
[1] "北京"
$school
[1] "清华大学"
六、遍历列表
1. 遍历值
r
student <- list(name = "张三", age = 20, scores = c(92, 85, 78))
for (item in student) {
print(item)
}
运行结果:
txt
[1] "张三"
[1] 20
[1] 92 85 78
2. 同时遍历名称和值
r
student <- list(name = "张三", age = 20, scores = c(92, 85, 78))
for (key in names(student)) {
print(paste(key, ":", paste(student[[key]], collapse = ", ")))
}
运行结果:
txt
[1] "name : 张三"
[1] "age : 20"
[1] "scores : 92, 85, 78"
3. 用 lapply 批量操作(推荐)
lapply 对列表每个元素应用一个函数,返回新列表:
r
scores <- list(
math = c(92, 85, 78),
chinese = c(88, 72, 95),
english = c(76, 90, 82)
)
# 计算每科平均分
averages <- lapply(scores, mean)
print(averages)
运行结果:
txt
$math
[1] 85
$chinese
[1] 85
$english
[1] 82.6666666666667
lapply 是 R 函数式编程的精髓,比手写 for 循环更简洁。
七、嵌套列表(列表中套列表)
r
class_info <- list(
class_name = "高三一班",
students = list(
list(name = "张三", age = 18, score = 92),
list(name = "李四", age = 19, score = 85),
list(name = "王五", age = 18, score = 78)
)
)
# 访问嵌套元素
print(class_info$class_name)
print(class_info$students[[1]]$name)
print(class_info$students[[2]]$score)
运行结果:
txt
[1] "高三一班"
[1] "张三"
[1] 85
逐层剥洋葱:class_info → students → 第1个学生 → name。
八、综合实战练习(可直接复制运行)
r
# ==============================
# R 综合练习:列表实战
# 场景:学生信息管理系统
# ==============================
# 1. 创建多个学生信息(列表的列表)
students <- list(
list(name = "张三", age = 20, scores = c(数学 = 92, 语文 = 85, 英语 = 78)),
list(name = "李四", age = 21, scores = c(数学 = 88, 语文 = 72, 英语 = 90)),
list(name = "王五", age = 19, scores = c(数学 = 76, 语文 = 95, 英语 = 82)),
list(name = "赵六", age = 20, scores = c(数学 = 65, 语文 = 58, 英语 = 70)),
list(name = "孙七", age = 22, scores = c(数学 = 95, 语文 = 88, 英语 = 92))
)
# 2. 遍历并打印每个学生的信息
print("=== 学生信息 ===")
for (i in 1:length(students)) {
s <- students[[i]]
avg <- mean(s$scores)
print(paste(s$name, ",年龄", s$age, ",平均分", round(avg, 1)))
}
# 3. 找出平均分最高的学生
print("=== 最高平均分 ===")
max_avg <- 0
best_student <- ""
for (s in students) {
avg <- mean(s$scores)
if (avg > max_avg) {
max_avg <- avg
best_student <- s$name
}
}
print(paste(best_student, ",平均分", round(max_avg, 1)))
# 4. 统计每科平均分(提取所有学生的各科成绩)
print("=== 各科平均分 ===")
subjects <- c("数学", "语文", "英语")
for (subj in subjects) {
total <- 0
for (s in students) {
total <- total + s$scores[subj]
}
print(paste(subj, ":", round(total / length(students), 1)))
}
# 5. 找出有不及格科目的学生
print("=== 有不及格科目的学生 ===")
for (s in students) {
if (any(s$scores < 60)) {
failed <- names(s$scores[s$scores < 60])
for (f in failed) {
print(paste(s$name, "的", f, "不及格:", s$scores[f], "分"))
}
}
}
运行结果:
txt
[1] "=== 学生信息 ==="
[1] "张三 ,年龄 20 ,平均分 85"
[1] "李四 ,年龄 21 ,平均分 83.3"
[1] "王五 ,年龄 19 ,平均分 84.3"
[1] "赵六 ,年龄 20 ,平均分 64.3"
[1] "孙七 ,年龄 22 ,平均分 91.7"
[1] "=== 最高平均分 ==="
[1] "孙七 ,平均分 91.7"
[1] "=== 各科平均分 ==="
[1] "数学 : 83.2"
[1] "语文 : 79.6"
[1] "英语 : 82.4"
[1] "=== 有不及格科目的学生 ==="
[1] "赵六 的 语文 不及格: 58 分"