scala中的集合
Scala的集合类可以从三个维度进行切分:
- 可变与不可变集合(Immutable and mutable collections)
- 静态与延迟加载集合 (Eager and delayed evaluation )
- 串行与并行计算集合(Sequential and parallel evaluation )
可变与不可变集合[1]
可变集合可以在适当的地方被更新或扩展。这意味着你可以修改,添加,移除一个集合的元素。
而不可变集合类,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。
所有的集合类都可以在包scala.collection
或scala.collection.mutable
,scala.collection.immutable
,scala.collection.generic
中找到。
下面的图表显示了scala.collection
包中所有的集合类。这些都是高级抽象类或特性,它们通常具备和不可变实现一样的可变实现。
下面的图表显示scala.collection.immutable
中的所有集合类。
下面的图表显示scala.collection.mutable
中的所有集合类。
代码需要的大部分集合类都独立地存在于3种变体中,它们位于scala.collection
, scala.collection.immutable
, scala.collection.mutable
包。每一种变体在可变性方面都有不同的特征。
collection.generic
包含了集合的构建块。集合类延迟了collection.generic
类中的部分操作实现,另一方面集合框架的用户仅仅需要在异常环境中引用collection.generic
的类。
scala.collection.immutable
包是的集合类确保不被任何对象改变。例如一个集合创建之后将不会改变。因此,你可以确信的是在不同的位置和时间去访问同一个不可变集合的值,你将总是得到相同的元素。scala.collection.mutable
包的集合类则有一些操作可以修改集合。所以处理可变集合意味着你需要去理解哪些操作会导致集合改变。scala.collection
包中的集合,既可以是可变的,也可以是不可变的。scala.collection
包中的根集合类中定义了和不可变集合相同的接口,同时,scala.collection.mutable
包中的可变集合类代表性地往这个接口中添加了一些辅助作用的修改操作。- 例如:collection.IndexedSeq[T]] 就是 collection.immutable.IndexedSeq[T] 和collection.mutable.IndexedSeq[T]这两类的超类。
- 根集合类与不可变集合类之间的区别:不可变集合类可以确保没有人可以修改集合。然而,根集合类仅保证不修改集合本身。即使这个集合类没有提供修改集合的静态操作,它仍然可能在运行时作为可变集合被其它客户端所修改。
默认情况下,Scala 一直采用不可变集合类。例如,如果你仅写了Set
而没有任何加前缀也没有从其它地方导入Set
,你会得到一个不可变的set
,另外如果你写迭代,你也会得到一个不可变的迭代集合类,这是由于这些类在从scala中导入的时候都是默认绑定的。为了得到可变的默认版本,你需要显式的声明collection.mutable.Set
或collection.mutable.Iterable
。
一个有用的约定,如果你想要同时使用可变和不可变集合类,只导入collection.mutable包即可。
import scala.collection.mutable
mutable.Set // 可变
Set // 不可变
静态与延迟加载集合[2]
我们来解释一个概念:transformation。集合中有大量的操作都是把一个集合“转换”成另一个集合,比如map
,filter
等等。
而Eager和Delayed集合的区别在于:Eager集合总是立即为元素分配内存,当遇到一个transform动作时,Eager的集合会直接计算并返回结果,而Delayed集合则会尽可能晚的推迟执行,直到必须返回结果时才去执行。这一点和Spark RDD操作中的transformation和action非常类似。
在现有的集合里,只有Stream是Lasy的,所有其他的集合都是静态(Eager)加载的。但是你可以很容易地把一个静态集合转换成lazy的,那就是创建一个view。
关于集合的种类以及其他特性,参见参考资料[2]。他那边整理了一个表格,大家可以去看看。
操作方法
scala中的集合操作分为两类:转换操作(transformation )和行动操作(actions)(有些人喜欢叫他为聚合操作)。第一种操作类型将集合转换为另一个集合,第二种操作类型返回某些类型的值。
常用操作符
scala中的操作符也是类中的方法:
++ 从列表的尾部添加另外一个列表
++: 在列表的头部添加一个列表
+: 在列表的头部添加一个元素
:+ 在列表的尾部添加一个元素
:: 在列表的头部添加一个元素
::: 在列表的头部添加另外一个列表
val left = List(1,2,3)
val right = List(4,5,6)
//以下操作等价
left ++ right // List(1,2,3,4,5,6)
left ++: right // List(1,2,3,4,5,6)
right.++:(left) // List(1,2,3,4,5,6)
right.:::(left) // List(1,2,3,4,5,6)
//以下操作等价
0 +: left //List(0,1,2,3)
left.+:(0) //List(0,1,2,3)
//以下操作等价
left :+ 4 //List(1,2,3,4)
left.:+(4) //List(1,2,3,4)
//以下操作等价
0 :: left //List(0,1,2,3)
left.::(0)