第九章:列表 List 数据类型

列表(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 分"
相关推荐
刘马想放假2 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠3 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦10 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠11 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾11 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82111 天前
算法复键——树状数组
数据结构·算法
GZ同学11 天前
单双变量Ripley’s K函数 R 语言实现
开发语言·r语言
牛油果子哥q11 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒11 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记11 天前
单项不带头不循环链表
数据结构·链表