文章目录

Scala 集合操作:map、filter、fold

发布于 2026-04-08 08:16:00 · 浏览 7 次 · 评论 0 条

Scala 集合操作:map、filter、fold

Scala 的集合库是其最强大的功能之一,允许开发者以声明式的方式处理数据。掌握 map(转换)、filter(筛选)和 fold(聚合)这三个核心操作,足以应对绝大多数数据处理场景。


准备工作

在开始编写代码之前,确保你的开发环境已经配置好。

  1. 打开 IntelliJ IDEA 或 VS Code 等集成开发环境。
  2. 创建一个新的 Scala Worksheet 文件(后缀名为 .sc),这样可以实时看到代码的运行结果。
  3. 定义一组基础数据用于后续操作。输入以下代码:
val numbers = List(1, 2, 3, 4, 5)
val words = List("scala", "java", "python", "c++")

1. map:数据的“一对一”转换

map 的作用是将集合中的每一个元素取出,应用一个函数后,生成一个新的集合。新集合的元素数量与原集合保持一致。

基础用法

目标:将 numbers 列表中的每个数字乘以 2。

  1. 调用 Listmap 方法。
  2. 传入一个匿名函数,参数 x 代表列表中的每一个元素。
  3. 编写转换逻辑 x * 2

输入以下代码:

val doubled = numbers.map(x => x * 2)
// 结果: List(2, 4, 6, 8, 10)

字符串处理

目标:将 words 列表中的所有单词转换为首字母大写。

  1. 使用 map 遍历字符串列表。
  2. 调用 String 的 capitalize 方法。

输入以下代码:

val capitalized = words.map(word => word.capitalize)
// 结果: List("Scala", "Java", "Python", "C++")

语法糖简写

在 Scala 中,当函数参数只出现一次时,可以使用下划线 _ 作为占位符来简化代码。

修改上面的乘法代码:

val doubledShort = numbers.map(_ * 2)

2. filter:数据的“条件筛选”

filter 的作用是根据给定的条件保留元素。如果条件返回 true,则保留该元素;否则将其丢弃。

基础筛选

目标:从 numbers 中筛选出所有的偶数。

  1. 调用 filter 方法。
  2. 编写判断逻辑:x % 2 == 0(即 x 除以 2 的余数为 0)。

输入以下代码:

val evens = numbers.filter(x => x % 2 == 0)
// 结果: List(2, 4)

字符串长度筛选

目标:从 words 中筛选出长度小于 5 的单词。

  1. 调用 filter 方法。
  2. 访问字符串的 length 属性进行比较。

输入以下代码:

val shortWords = words.filter(w => w.length < 5)
// 结果: List("java", "c++")

3. fold:数据的“聚合”计算

mapfilter 都是保持集合类型的操作,而 fold 则是将集合元素“折叠”成一个值。它需要一个初始值和一个聚合函数。最常用的是 foldLeft,它从左向右遍历。

基础求和

目标:计算 numbers 列表中所有数字的总和。

  1. 调用 foldLeft 方法。
  2. 设置初始值为 0(因为加法的单位元是 0)。
  3. 编写聚合逻辑:(累加器, 当前元素) => 累加器 + 当前元素

输入以下代码:

val sum = numbers.foldLeft(0)((acc, x) => acc + x)
// 过程解析:
// 初始 acc=0
// 1. acc=0, x=1 -> new acc=1
// 2. acc=1, x=2 -> new acc=3
// 3. acc=3, x=3 -> new acc=6
// ...
// 结果: 15

为了更直观地理解 foldLeft 的执行流程,可以参考以下逻辑:

graph LR A[Start] -->|Init: 0| B[Step 1: acc=0, x=1] B -->|Result: 1| C[Step 2: acc=1, x=2] C -->|Result: 3| D[Step 3: acc=3, x=3] D -->|Result: 6| E[Step 4: acc=6, x=4] E -->|Result: 10| F[Step 5: acc=10, x=5] F -->|Result: 15| G[End] style A fill:#f9f,stroke:#333,stroke-width:2px style G fill:#f9f,stroke:#333,stroke-width:2px

字符串拼接

目标:将 words 列表拼接成一个单独的字符串,中间用逗号分隔。

  1. 设置初始值为空字符串 ""
  2. 编写逻辑:如果是累加器的第一次累加(初始值),直接加单词;否则先加逗号再加单词。
  3. 或者使用更简单的 mkString 方法,但为了练习 fold,我们手动实现。

输入以下代码:

// 使用 foldLeft 实现简易 mkString
val csvString = words.foldLeft("")((acc, word) => 
  if (acc.isEmpty) word else s"$acc,$word"
)
// 结果: "scala,java,python,c++"

fold 语法糖

对于累加这种常见操作,Scala 提供了更简洁的写法。

  1. 使用 /: 操作符代替 foldLeft

输入以下代码:

val sumShort = (0 /: numbers)(_ + _)

4. 综合实战:链式操作

在实际开发中,通常会将这三个操作组合在一起使用,形成处理流水线。

目标:计算 numbers 列表中所有“偶数”的“平方”之和。

逻辑拆解:

  1. 过滤出偶数:2, 4
  2. 转换为平方:4, 16
  3. 聚合求和:20

输入以下代码:

val result = numbers
  .filter(x => x % 2 == 0) // 第一步:筛选偶数
  .map(x => x * x)        // 第二步:计算平方
  .foldLeft(0)(_ + _)     // 第三步:求和

// 结果: 20 (即 2*2 + 4*4 = 4 + 16)

为了清晰地展示这三个方法的区别,请参考下表:

方法名 核心作用 输入元素类型 输出结果类型 典型场景
map 转换(变形) A List[B] 数据类型转换、属性提取
filter 筛选(保留) A List[A] 去除无效数据、条件查询
fold 聚合(归约) A B (通常是单个值) 求和、求积、拼接字符串

5. 高阶技巧:使用模式匹配

mapfilter 中,可以结合 Scala 强大的模式匹配来处理复杂结构。

场景:假设有一个包含“年龄”和“姓名”的元组列表,找出所有成年人(年龄 >= 18),并提取他们的名字。

  1. 定义数据源:
val people = List((12, "Alice"), (20, "Bob"), (15, "Charlie"), (30, "David"))
  1. 执行链式操作:
val adultsNames = people
  .filter { case (age, _) => age >= 18 } // 使用模式匹配解构元组
  .map { case (_, name) => name }        // 只提取 name 部分

// 结果: List("Bob", "David")

这里利用了 case 语句自动解构元组,无需手动通过 _1_2 访问元素,代码可读性更高。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文