13 Collection 容器

久未见 提交于 2019-12-26 11:43:54

  • 官方collection教程
  • 所有collection扩展自Iterable特质
  • 三大类,序列,集合,映射 seq set map
  • 对于几乎所有的collection,都提供了可变和不可变的版本
  • 列表要么是空的,要么是一头一尾,尾是列表
  • 集合没有先后次序
  • + 将元素添加到无先后次序的容器中,+: 和 :+向前或向后追加到序列,++将两个集合串接到一起,-和–移除元素(1个减号和两个减号)
  • Iterable和Seq特质有数十个常见操作方法,很丰富
  • 映射、折叠和拉链

主要的collection特质

  • 下面请欣赏一组图片,注意蓝底白字(特质trait)和黑底白字(类class),虚线(隐式转换)和粗实线(默认实现)、细实线(通过类实现)图片来源
  • 首先是scala.collection
    在这里插入图片描述
  • scala.collection.immutable
    在这里插入图片描述
  • scala.collection.mutable
    在这里插入图片描述
  • 图例
    在这里插入图片描述
  • Iterable指的是那些能够交出用来访问集合中所有元素的Iterator的集合
val coll = List(2,1,4,3)  //任意Iterable特质的类
val iter = coll.iterator
while (iter.hasNext){println(iter.next())}
  • Seq是一个有先后次序的值的序列,例如数组或列表,IndexedSeq可以通过整型下标快速访问任意元素,ArrayBuffer带下标但链表不带。
  • Set是一组没有先后次序的值。
  • Map是一组键值的对偶。
  • 每一个collection特质或类都带有一个apply方法的伴生对象,这个apply方法可以用来构建collection中的实例。
  • 上面的三个图中出现的特质或类,统统可以直接拿来创建实例。图中粗实线是默认实现的关系,不管是Seq还是Iterable,默认的都是List
scala> Seq(1,2,3)
res1: Seq[Int] = List(1, 2, 3)

scala> Iterable(1,2,3)
res2: Iterable[Int] = List(1, 2, 3)
  • 不同collection之间的转换,可以调用toXX方法,和to[C]的泛型方法
scala> val list = List(1,2,3)
list: List[Int] = List(1, 2, 3)

scala> list.toVector
res5: Vector[Int] = Vector(1, 2, 3)

scala> list.to[Vector]
res6: Vector[Int] = Vector(1, 2, 3)
  • 使用==操作符实现任何seq、set、map的比较,如果不同类的collection比较,可以使用sameElements方法比较元素是否是相同。
scala> list == Vector(1,2,3)
res8: Boolean = true

scala> list == Set(1,2,3)
res9: Boolean = false

scala> list sameElements Set(1,2,3,2)
res10: Boolean = true

可变和不可变的collection

  • 不可变的collection可以安全共享引用,在多线程的应用程序中也无妨,scala.collection.Map, scala.collection.mutable.Map, scala.collection.immutable.Map,第一个是第二个和第三个的超类型
  • scala优先采用不可变集合,scala包和Predef对象里还有指向不可变特质的类型别名List、Set、Map。
  • 使用可变的,import scala.collection.mutable,然后使用mutable.Map就是可变的了。

序列Seq

  • 不可变的Seq
    在这里插入图片描述
  • 可变的Seq
    在这里插入图片描述
  • 对比上面两个图可以看出,不可变版的默认实现是Vector,可变版本的默认实现是ArrayBuffer。
  • Vector支持快速随机访问,是以树形结构的形式实现,每个节点可以有不超过32个子节点,速度很快
  • Range表示一个整数序列,只存储开始值、结束值、增值,可以使用to和until方法构造Range对象
  • 此外还有栈、队列、优先级队列等
scala> Range(1,10)
res16: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> Range(1,10,2)
res17: scala.collection.immutable.Range = Range(1, 3, 5, 7, 9)

scala> 1 until 10
res18: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> 1 to 10
res19: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
//栈
scala> val a =  collection.mutable.Stack(1,2,3)
a: scala.collection.mutable.Stack[Int] = Stack(1, 2, 3)
//入栈
scala> a.push(10)
res19: a.type = Stack(10, 1, 2, 3)
//出栈
scala> a.pop
res20: Int = 10

scala> a
res21: scala.collection.mutable.Stack[Int] = Stack(1, 2, 3)
//队列
scala> val b =  collection.mutable.Queue(1,2,3,4)
b: scala.collection.mutable.Queue[Int] = Queue(1, 2, 3, 4)
//入队
scala> b.enqueue(7)
//出队
scala> b.dequeue
res23: Int = 1

列表

  • 列表只有头和尾,head和tail,空列表Nil,head是第一个元素,tail是除了第一个元素以外的所有元素。
scala> val list = List(1,2,3,4)
list: List[Int] = List(1, 2, 3, 4)

scala> list.head
res24: Int = 1

scala> list.tail
res25: List[Int] = List(2, 3, 4)

scala> List(1).tail
res26: List[Int] = List()
  • 从给定的head和tail创建新列表 使用::操作符,这个操作符是右结合的,其右边需要是个List
scala> 100::list
res28: List[Int] = List(100, 1, 2, 3, 4)
//下面的错误
scala> list :: 100
<console>:13: error: value :: is not a member of Int
       list :: 100
       
scala> list ::list
res30: List[Any] = List(List(1, 2, 3, 4), 1, 2, 3, 4)
//使用递归访问列表,当然比较低效,下面的代码就出现了java.lang.StackOverflowError
def sum(lst:List[Int]):Double={
  if (lst == Nil) 0 else (lst.head * 1.0) + sum(lst.tail)
}
val a = (1 to 100000).toList
//使用模式匹配计算,同样的错误
def sum2(lst:List[Int]):Int=lst match{
  case Nil => 0
  case h :: t => h+sum2(t)
}
  • 可别版本的List使用ListBuffer,链表支撑的数据结构,高效地从任意一端添加或移除元素,但是添加或移除元素并不高效。

集 Set

  • Set是不重复的元素的collection,默认顺序是hashcode方法进行组织,这样查找元素比在数组或列表中更快
scala> val s = Set(1,2,3)
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> s+1
res34: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
  • 链式哈希set可以保留元素的插入顺序LinkedHashSet
//多参数
scala> Set(1 to 5: _*)
res8: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)

scala> for(i <- Set(1,2,3,4,5,6)) println(i)
5
1
6
2
3
4

scala>  val s1 = collection.mutable.LinkedHashSet(1,2,3,4,5,6)
s1: scala.collection.mutable.LinkedHashSet[Int] = Set(1, 2, 3, 4, 5, 6)

scala> for(i <- s1) println(i)
1
2
3
4
5
6

  • 已排序集合 SortedSet
scala> collection.mutable.SortedSet(5,1,3,2,4)
res11: scala.collection.mutable.SortedSet[Int] = TreeSet(1, 2, 3, 4, 5)
  • 位组集合,BitSet,以一个字符序列的方式存放非负整数,只能是正的Int型的,不能太大,也不能是其他类型的。如果位组中有i,那么低i个字位是1。
scala> collection.immutable.BitSet(1,2,3,2)
res35: scala.collection.immutable.BitSet = BitSet(1, 2, 3)

scala> collection.immutable.BitSet(1,2,2100000000)
java.lang.OutOfMemoryError: Java heap space
  • contains方法检查一个集合是不是包含某个元素,subsetOf方法检查某个集合是否被另一个集合包含
  • 集合的运算,交集、并集、差集,符号太麻烦,还是记忆union intersect diff简单
操作 方法 符号1 符号2
union | ++
intersect &
diff &~ --
scala> val s1 = Set(1,2,3)
s1: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> val s2 = Set(2,3,4)
s2: scala.collection.immutable.Set[Int] = Set(2, 3, 4)

scala> val s3 = Set(7,8)
s3: scala.collection.immutable.Set[Int] = Set(7, 8)

scala> s1.union(s2)
res38: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)

scala> s1.intersect(s2)
res39: scala.collection.immutable.Set[Int] = Set(2, 3)

scala> s1.diff(s2)
res40: scala.collection.immutable.Set[Int] = Set(1)

scala> s3.intersect(s1)
res41: scala.collection.immutable.Set[Int] = Set()

添加或去除元素的操作符

  • 当你想添加或删除某个元素或某些元素时,操作符取决于容器类型
  1. coll(k) , 即coll.apply(k)
    排在第k位的元素,或键k对应的映射值,适合Seq,Map
  2. coll :+ elem 或 elem +: coll,向后追加或向前追加了elem的与coll类型相同的容器,适合Seq。冒号靠近coll
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)

scala> a :+ 4
res0: List[Int] = List(1, 2, 3, 4)

scala> 4 +: a
res1: List[Int] = List(4, 1, 2, 3)
  1. coll + elem 或 coll + (e1,e2,…)添加了给定元素的与coll相同的容器,适合Set Map
scala> val s = Set(1,2,3)
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> s + 5
res2: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 5)

scala> s + (6,7)
res3: scala.collection.immutable.Set[Int] = Set(1, 6, 2, 7, 3)
  1. coll - elem 或 coll - (e1,e2,…)移除了给定元素的与coll相同的容器,适合Set Map ArrayBuffer
scala> s - 1
res4: scala.collection.immutable.Set[Int] = Set(2, 3)

scala> s - (2,3)
res5: scala.collection.immutable.Set[Int] = Set(1)
  1. coll ++ coll2或coll2 ++: coll,与coll类型相同的容器,同时包含两个容器,适用于Iterable
scala> val r = 1 to 10
r: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> val l = List(20,22)
l: List[Int] = List(20, 22)

scala> r ++ l
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 22)

scala> r ++: l
res8: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 22)

scala> s ++ r
res9: scala.collection.immutable.Set[Int] = Set(5, 10, 1, 6, 9, 2, 7, 3, 8, 4)

scala> r ++ s
res10: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3)

  1. coll --coll2,移除coll中的coll2,相当于diff,适用于Set Map ArrayBuffer
scala> s -- r
res15: scala.collection.immutable.Set[Int] = Set()
  1. elem :: lst,lst2 ::: lst,追加到lst中,适用于List ,带冒号的是右结合的,左边的元素添加都右边
    三个冒号和 ++: 一样,两个冒号和 +: 一样
scala> 1 :: List(3,4)
res19: List[Int] = List(1, 3, 4)

scala> List(1,2) :: List(3,4)
res20: List[Any] = List(List(1, 2), 3, 4)

scala> List(1,2) ::: List(3,4)
res21: List[Int] = List(1, 2, 3, 4)

scala> List(1,2) ++: List(3,4)
res22: List[Int] = List(1, 2, 3, 4)

scala> List(1,2) +: List(3,4)
res23: List[Any] = List(List(1, 2), 3, 4)

  1. set | set2 , set & set2 ,set &~ set2,并交差集,适用于Set
  2. coll += elem,coll += (e1,e2,…) ,coll ++= coll2 ,coll -= elem,coll -= (e1,e2,…) ,coll --= coll2,通过添加或移除元素修改coll,适用于可变的collection
scala> val s = collection.mutable.Set(1,2,3)
s: scala.collection.mutable.Set[Int] = Set(1, 2, 3)

scala> s += 4
res24: s.type = Set(1, 2, 3, 4)

scala> s += (5,6,7)
res25: s.type = Set(1, 5, 2, 6, 3, 7, 4)

scala> s ++= Set(8,9)
res26: s.type = Set(9, 1, 5, 2, 6, 3, 7, 4, 8)

scala> s -= (1,2,3)
res27: s.type = Set(9, 5, 6, 7, 4, 8)

scala> s --= Set(9,10,11)
res28: s.type = Set(5, 6, 7, 4, 8)

  1. elem +=: coll,coll2 ++=:coll1,通过向前追加给定元素修改coll,适合ArrayBuffer
scala> val a = collection.mutable.ArrayBuffer(1,2)
a: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2)

scala> 4 +=: a
res30: a.type = ArrayBuffer(4, 1, 2)

scala> a += 5
res32: a.type = ArrayBuffer(4, 1, 2, 5)

scala> List(7,8) ++=: a
res33: a.type = ArrayBuffer(7, 8, 4, 1, 2, 5)

常用方法

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!