List & Set
一、List字面量
List 是 Scala 中非常重要的一个数据结构,其与 Array(数组) 非常类似,但是 List 是不可变的,和 Java 中的 List 一样,其底层实现是链表。
1 | scala> val list = List("hadoop", "spark", "storm") |
二、List类型
Scala 中 List 具有以下两个特性:
- 同构 (homogeneous):同一个 List 中的所有元素都必须是相同的类型;
- 协变 (covariant):如果 S 是 T 的子类型,那么
List[S]
就是List[T]
的子类型,例如List[String]
是List[Object]
的子类型。
需要特别说明的是空列表的类型为 List[Nothing]
:
1 | scala> List() |
三、构建List
所有 List 都由两个基本单元构成:Nil
和 ::
(读作”cons”)。即列表要么是空列表 (Nil),要么是由一个 head 加上一个 tail 组成,而 tail 又是一个 List。我们在上面使用的 List("hadoop", "spark", "storm")
最终也是被解释为 "hadoop"::"spark":: "storm"::Nil
。
1 | scala> val list01 = "hadoop"::"spark":: "storm"::Nil |
四、模式匹配
Scala 支持展开列表以实现模式匹配。
1 | scala> val list = List("hadoop", "spark", "storm") |
如果只需要匹配部分内容,可以如下:
1 | scala> val a::rest=list |
五、列表的基本操作
5.1 常用方法
1 | object ScalaApp extends App { |
5.2 indices
indices 方法返回所有下标。
1 | scala> list.indices |
5.3 take & drop & splitAt
- take:获取前 n 个元素;
- drop:删除前 n 个元素;
- splitAt:从第几个位置开始拆分。
1 | scala> list take 2 |
5.4 flatten
flatten 接收一个由列表组成的列表,并将其进行扁平化操作,返回单个列表。
1 | scala> List(List(1, 2), List(3), List(), List(4, 5)).flatten |
5.5 zip & unzip
对两个 List 执行 zip
操作结果如下,返回对应位置元素组成的元组的列表,unzip
则执行反向操作。
1 | scala> val list = List("hadoop", "spark", "storm") |
5.6 toString & mkString
toString 返回 List 的字符串表现形式。
1 | scala> list.toString |
如果想改变 List 的字符串表现形式,可以使用 mkString。mkString 有三个重载方法,方法定义如下:
1 | // start:前缀 sep:分隔符 end:后缀 |
使用示例如下:
1 | scala> list.mkString |
5.7 iterator & toArray & copyToArray
iterator 方法返回的是迭代器,这和其他语言的使用是一样的。
1 | object ScalaApp extends App { |
toArray 和 toList 用于 List 和数组之间的互相转换。
1 | scala> val array = list.toArray |
copyToArray 将 List 中的元素拷贝到数组中指定位置。
1 | object ScalaApp extends App { |
六、列表的高级操作
6.1 列表转换:map & flatMap & foreach
map 与 Java 8 函数式编程中的 map 类似,都是对 List 中每一个元素执行指定操作。
1 | scala> List(1,2,3).map(_+10) |
flatMap 与 map 类似,但如果 List 中的元素还是 List,则会对其进行 flatten 操作。
1 | scala> list.map(_.toList) |
foreach 要求右侧的操作是一个返回值为 Unit 的函数,你也可以简单理解为执行一段没有返回值代码。
1 | scala> var sum = 0 |
6.2 列表过滤:filter & partition & find & takeWhile & dropWhile & span
filter 用于筛选满足条件元素,返回新的 List。
1 | scala> List(1, 2, 3, 4, 5) filter (_ % 2 == 0) |
partition 会按照筛选条件对元素进行分组,返回类型是 tuple(元组)。
1 | scala> List(1, 2, 3, 4, 5) partition (_ % 2 == 0) |
find 查找第一个满足条件的值,由于可能并不存在这样的值,所以返回类型是 Option
,可以通过 getOrElse
在不存在满足条件值的情况下返回默认值。
1 | scala> List(1, 2, 3, 4, 5) find (_ % 2 == 0) |
takeWhile 遍历元素,直到遇到第一个不符合条件的值则结束遍历,返回所有遍历到的值。
1 | scala> List(1, 2, 3, -4, 5) takeWhile (_ > 0) |
dropWhile 遍历元素,直到遇到第一个不符合条件的值则结束遍历,返回所有未遍历到的值。
1 | // 第一个值就不满足条件,所以返回列表中所有的值 |
span 遍历元素,直到遇到第一个不符合条件的值则结束遍历,将遍历到的值和未遍历到的值分别放入两个 List 中返回,返回类型是 tuple(元组)。
1 | scala> List(1, 2, 3, -4, 5) span (_ > 0) |
6.3 列表检查:forall & exists
forall 检查 List 中所有元素,如果所有元素都满足条件,则返回 true。
1 | scala> List(1, 2, 3, -4, 5) forall ( _ > 0 ) |
exists 检查 List 中的元素,如果某个元素已经满足条件,则返回 true。
1 | scala> List(1, 2, 3, -4, 5) exists (_ > 0 ) |
6.4 列表排序:sortWith
sortWith 对 List 中所有元素按照指定规则进行排序,由于 List 是不可变的,所以排序返回一个新的 List。
1 | scala> List(1, -3, 4, 2, 6) sortWith (_ < _) |
七、List对象的方法
上面介绍的所有方法都是 List 类上的方法,下面介绍的是 List 伴生对象中的方法。
7.1 List.range
List.range 可以产生指定的前闭后开区间内的值组成的 List,它有三个可选参数: start(开始值),end(结束值,不包含),step(步长)。
1 | scala> List.range(1, 5) |
7.2 List.fill
List.fill 使用指定值填充 List。
1 | scala> List.fill(3)("hello") |
7.3 List.concat
List.concat 用于拼接多个 List。
1 | scala> List.concat(List('a', 'b'), List('c')) |
八、处理多个List
当多个 List 被放入同一个 tuple 中时候,可以通过 zipped 对多个 List 进行关联处理。
1 | // 两个 List 对应位置的元素相乘 |
九、缓冲列表ListBuffer
上面介绍的 List,由于其底层实现是链表,这意味着能快速访问 List 头部元素,但对尾部元素的访问则比较低效,这时候可以采用 ListBuffer
,ListBuffer 提供了在常量时间内往头部和尾部追加元素。
1 | import scala.collection.mutable.ListBuffer |
十、集(Set)
Set 是不重复元素的集合。分为可变 Set 和不可变 Set。
10.1 可变Set
1 | object ScalaApp extends App { |
10.2 不可变Set
不可变 Set 没有 add 方法,可以使用 +
添加元素,但是此时会返回一个新的不可变 Set,原来的 Set 不变。
1 | object ScalaApp extends App { |
10.3 Set间操作
多个 Set 之间可以进行求交集或者合集等操作。
1 | object ScalaApp extends App { |
参考资料
- Martin Odersky . Scala 编程 (第 3 版)[M] . 电子工业出版社 . 2018-1-1
- 凯.S.霍斯特曼 . 快学 Scala(第 2 版)[M] . 电子工业出版社 . 2017-7