1. 概述
在这篇文章中,我们将探讨如何在 Scala 中遍历集合的同时访问当前元素的索引。
2. 使用 zip
方法
Scala 提供了多种方式来获取迭代时的索引。最直接的方式是使用 zip
方法将原始列表与另一个包含索引的列表合并。我们可以手动创建一个索引列表,然后通过 zip
将两个列表合并:
scala> val lst = List("a","b","c","d","e")
val lst: List[String] = List(a, b, c, d, e)
scala> lst.zip(List(0,1,2,3,4,5,6,7)).foreach(println)
(a,0)
(b,1)
(c,2)
(d,3)
(e,4)
⚠️ 注意:zip
方法返回的新列表长度等于两个输入列表中较短的那个。在上面的例子中,原始列表有 5 个元素,而我们传入的索引列表有 8 个元素,最终结果只保留了前 5 对。
3. 结合 Range
使用 zip
虽然上面的例子能跑通,但在实际开发中我们通常不知道集合的具体大小。为了解决这个问题,可以使用 Range
。✅ Range
可以像普通 List
一样迭代,但它不会将所有元素都加载到内存中(惰性求值),这在处理大数据集时非常高效。
我们可以使用 until
来创建一个 Range
:
scala> 0 until 5
val res0: scala.collection.immutable.Range = Range 0 until 5
scala> (0 until 5).toList
val res1: List[Int] = List(0, 1, 2, 3, 4)
接着用它来代替手动写的索引列表:
scala> lst.zip(0 until lst.size).foreach(println)
(a,0)
(b,1)
(c,2)
(d,3)
(e,4)
这样我们就得到了每个元素对应的索引。
4. 访问元组中的字段
细心的朋友已经发现,zip
返回的是一个由二元组组成的列表。如果需要分别访问元素和索引,Scala 提供了非常简洁的语法支持。比如下面这段代码打印出原始元素及其索引:
scala> lst.zip(0 until lst.size).foreach(tuple => println(s"original element: ${tuple._1} => index: ${tuple._2}"))
original element: a => index: 0
original element: b => index: 1
original element: c => index: 2
original element: d => index: 3
original element: e => index: 4
或者更优雅地使用模式匹配(case class 风格):
scala> lst.zip(0 until lst.size).foreach{ case (elem, idx) => println(s"original element: ${elem} => index: ${idx}")}
original element: a => index: 0
original element: b => index: 1
original element: c => index: 2
original element: d => index: 3
original element: e => index: 4
5. 使用 zipWithIndex
不过说实话,前面的做法有点绕。我们为了得到索引还额外创建了一个列表,再 zip 一下,看起来有点“脱裤子放屁”的感觉。❌ 如果数据量很大,这种方式还会带来不必要的内存开销。
幸好,Scala 给我们提供了更好的选择 —— zipWithIndex
方法:
scala> lst.zipWithIndex.foreach{ case (elem, idx) => println(s"original element: ${elem} => index: ${idx}")}
original element: a => index: 0
original element: b => index: 1
original element: c => index: 2
original element: d => index: 3
original element: e => index: 4
✅ 这种方式不需要手动构造索引列表,也不涉及中间结构,代码更加干净利落。
6. 总结
本文介绍了几种在 Scala 中遍历集合并同时获取索引的方法:
- 最基础的是使用
zip
+ 自定义索引列表; - 更实用的方式是结合
Range
实现动态索引; - 最推荐的做法是直接使用
zipWithIndex
,简单粗暴还高效。
对于日常开发来说,除非有特殊需求,否则直接上 zipWithIndex
就完事了。