scala集合
Posted 难以言喻wyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scala集合相关的知识,希望对你有一定的参考价值。
目录
1.集合简介
1.1scala的集合有三大类:
序列Seq,集Set,映射Map,所有的集合都扩展至Iterable特质
对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两 个包
不可变集合:scala.collection.immutable
可变集合:scala.collection.mutable
Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而 不会
对原对象进行修改。类似于 java 中的 String 对象
可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似 于 java 中 StringBuilder 对象
建议:操作集合时,不可变用操作符,可变用方法。操作符也不一定就会返回新对象,但大多是这样的,还是要具体看。
scala中集合类的定义比java要清晰不少
1.2不可变集合关系一览:
set和map是java中本来就有的,哈希表和二叉树实现是肯定都有的,seq是java没有的,List归属到seq了,则scala的list和java的list不是一个概念
IndexSeq下的range可以写成for循环中的1 to 3 也就是隐式转换加上方法调用
scala中的String就是java.lang.String,和集合无直接关系,所以是虚箭头,是通过Perdef中的低优先级隐式转换来做到的。经过隐式转换为一个包装类型后就可以当做集合,Array和string类似。
大家注意 Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map 可以支持排序
IndexedSeq 和 LinearSeq 的区别:
(1)IndexedSeq 是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集合,通过索引即可定位
(2)LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找
此类包装为了兼容java在scala中非常常见,scala中很多类型就是对java类型的包装或者仅仅是别名。
scala中可能会推荐更多地使用不可变集合。能用不可变就用不可变。
1.3可变集合关系继承图:
整体结构差不多,在序列中多了一个Buffer
2.数组
不可变和可变:
- 不可变指的是对象大小不可变,但是可以修改元素的值(不能修改那创建了也没有用对吧),需要注意这一点。而如果用了val不变量存储,那么指向对象的地址也不可变。
- 不可变集合在原集合上个插入删除数据是做不到的,只能返回新的集合。
泛型:
- 集合类型大多都是支持泛型,使用泛型的语法是[Type],不同于java的<Type>。
2.1不可变数组(Array)
分为两种定义方式:
第一种:
案例:
第二种:
案例:
2.2可变数组(ArrayBuffer)
定义变长数组 val arr01 = ArrayBuffer[Any](3, 2, 5)
(1)[Any]存放任意数据类型
(2)(3, 2, 5)初始化好的三个元素
(3)ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer
案例:
(1)ArrayBuffer 是有序的集合
(2)增加元素使用的是 append 方法(),支持可变参数
2.3不可变数组和可变数组的转换
arr1.toBuffer //不可变数组转可变数组
arr2.toArray //可变数组转不可变数组
(1)arr2.toArray 返回结果才是一个不可变数组,arr2 本身没有变化
(2)arr1.toBuffer 返回结果才是一个可变数组,arr1 本身没有变化
案例:
2.4多维数组
二维数组:就是数组的数组
案例:
3.列表List
3.1不可变List
(1)List 默认为不可变集合
(2)创建一个 List(数据有顺序,可重复)
(3)遍历 List
(4)List 增加数据
(5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化
(6)取指定数据
(7)空集合 null
案例:
总结:
List,抽象类,不能直接new,使用伴生对象apply传入元素创建。
List本身也有apply能随机访问(做了优化),但是不能update更改。
foreach方法遍历。
支持+: :+首尾添加元素。
Nil空列表,::添加元素到表头。
常用Nil.::(elem)创建列表,换一种写法就是10 :: 20 :: 30 :: Nil得到结果List(10, 20, 30),糖是真滴多!
合并两个列表:list1 ::: list2 或者list1 ++ list2。
3.2可变ListBuffer
(1)创建一个可变集合 ListBuffer
(2)向集合中添加数据
(3)打印集合数据
案例:
总结:
可变列表ListBuffer,和ArrayBuffer很像。
final的,可以直接new,也可以伴生对象apply传入元素创建(总体来说scala中更推荐这种方式)。
方法:append prepend insert remove
添加元素到头或尾:+=: +=
合并:++得到新的列表,++=合并到源上。
删除元素也可以用-=运算符。
具体操作很多,使用时阅读文档即可。
4.Set集合
默认情况下,Scala 使用的是不可变集合,如果你想使用可变集合,需要引用
scala.collection.mutable.Set 包
4.1不可变Set
案例:
总结:
数据无序,不可重复。
可变和不可变都叫Set,需要做区分。默认Set定义为immutable.Set别名。
创建时重复数据会被去除,可用来去重。
添加元素:set + elem
合并:set1 ++ set2
移除元素:set - elem
不改变源集合。
4.2可变mutableSet
案例:
操作基于源集合做更改。
为了与不可变集合区分,import scala.collection.mutable并用mutable.Set。
不可变集合有的都有。
添加元素到源上:set += elem add
删除元素:set -= elem remove
合并:set1 ++= set2
都很简单很好理解,多看文档和源码就行。
5.Map集合
Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value) 映射
5.1不可变Map
案例:
5.2可变Map
案例:
6.元组
元组可以理解为一个容器,可以存放各种相同或者不同类型的数据,也就是将无关的数据封装为一个整合体。
注意:元组最大只能有22个元素。swap方法可以将只有两个元素的一个元组其中内容相互调换
案例:
Scala 系列—— 集合类型综述
一、集合简介
Scala中拥有多种集合类型,主要分为可变的和不可变的集合两大类:
- 可变集合: 可以被修改。即可以更改,添加,删除集合中的元素;
- 不可变集合类:不能被修改。对集合执行更改,添加或删除操作都会返回一个新的集合,而不是修改原来的集合。
二、集合结构
Scala中的大部分集合类都存在三类变体,分别位于scala.collection
, scala.collection.immutable
, scala.collection.mutable
包中。还有部分集合类位于scala.collection.generic
包下。
- scala.collection.immutable :包是中的集合是不可变的;
- scala.collection.mutable :包中的集合是可变的;
- scala.collection :包中的集合,既可以是可变的,也可以是不可变的。
val sortSet = scala.collection.SortedSet(1, 2, 3, 4, 5)
val mutableSet = collection.mutable.SortedSet(1, 2, 3, 4, 5)
val immutableSet = collection.immutable.SortedSet(1, 2, 3, 4, 5)
如果你仅写了Set
而没有加任何前缀也没有进行任何import
,则Scala默认采用不可变集合类。
scala> Set(1,2,3,4,5)
res0: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)
3.1 scala.collection
scala.collection包中所有集合如下图:
3.2 scala.collection.mutable
scala.collection.mutable包中所有集合如下图:
3.2 scala.collection.immutable
scala.collection.immutable包中所有集合如下图:
三、Trait Traversable
Scala中所有集合的顶层实现是Traversable
。它唯一的抽象方法是foreach
:
def foreach[U](f: Elem => U)
实现Traversable
的集合类只需要实现这个抽象方法,其他方法可以从Traversable
继承。Traversable
中的所有可用方法如下:
方法 | 作用 |
---|---|
Abstract Method: | |
xs foreach f |
为 xs 的每个元素执行函数 f |
Addition: | |
xs ++ ys |
一个包含 xs 和 ys 中所有元素的新的集合。 ys 是一个 Traversable 或 Iterator。 |
Maps: | |
xs map f |
对 xs 中每一个元素应用函数 f,并返回一个新的集合 |
xs flatMap f |
对 xs 中每一个元素应用函数 f,最后将结果合并成一个新的集合 |
xs collect f |
对 xs 中每一个元素调用偏函数 f,并返回一个新的集合 |
Conversions: | |
xs.toArray |
将集合转化为一个 Array |
xs.toList |
将集合转化为一个 List |
xs.toIterable |
将集合转化为一个 Iterable |
xs.toSeq |
将集合转化为一个 Seq |
xs.toIndexedSeq |
将集合转化为一个 IndexedSeq |
xs.toStream |
将集合转化为一个延迟计算的流 |
xs.toSet |
将集合转化为一个 Set |
xs.toMap |
将一个(key, value)对的集合转化为一个Map。 如果当前集合的元素类型不是(key, value)对形式, 则报静态类型错误。 |
Copying: | |
xs copyToBuffer buf |
拷贝集合中所有元素到缓存 buf |
xs copyToArray(arr,s,n) |
从索引 s 开始,将集合中最多 n 个元素复制到数组 arr。 最后两个参数是可选的。 |
Size info: | |
xs.isEmpty |
判断集合是否为空 |
xs.nonEmpty |
判断集合是否包含元素 |
xs.size |
返回集合中元素的个数 |
xs.hasDefiniteSize |
如果 xs 具有有限大小,则为真。 |
Element Retrieval: | |
xs.head |
返回集合中的第一个元素(如果无序,则随机返回) |
xs.headOption |
以 Option 的方式返回集合中的第一个元素, 如果集合为空则返回 None |
xs.last |
返回集合中的最后一个元素(如果无序,则随机返回) |
xs.lastOption |
以 Option 的方式返回集合中的最后一个元素, 如果集合为空则返回 None |
xs find p |
以 Option 的方式返回满足条件 p 的第一个元素, 如果都不满足则返回 None |
Subcollection: | |
xs.tail |
除了第一个元素之外的其他元素组成的集合 |
xs.init |
除了最后一个元素之外的其他元素组成的集合 |
xs slice (from, to) |
返回给定索引范围之内的元素组成的集合 (包含 from 位置的元素但不包含 to 位置的元素) |
xs take n |
返回 xs 的前n个元素组成的集合(如果无序,则返回任意n个元素) |
xs drop n |
返回 xs 的后n个元素组成的集合(如果无序,则返回任意n个元素) |
xs takeWhile p |
从第一个元素开始查找满足条件 p 的元素, 直到遇到一个不满足条件的元素,返回所有遍历到的值。 |
xs dropWhile p |
从第一个元素开始查找满足条件 p 的元素, 直到遇到一个不满足条件的元素,返回所有未遍历到的值。 |
xs filter p |
返回满足条件 p 的所有元素的集合 |
xs withFilter p |
集合的非严格的过滤器。后续对 xs 调用方法 map、flatMap 以及 withFilter 都只用作于满足条件 p 的元素,而忽略其他元素 |
xs filterNot p |
返回不满足条件 p 的所有元素组成的集合 |
Subdivisions: | |
xs splitAt n |
在给定位置拆分集合,返回一个集合对 (xs take n, xs drop n) |
xs span p |
根据给定条件拆分集合,返回一个集合对(xs takeWhile p, xs dropWhile p)。即遍历元素,直到遇到第一个不符合条件的值则结束遍历,将遍历到的值和未遍历到的值分别放入两个集合返回。 |
xs partition p |
按照筛选条件对元素进行分组 |
xs groupBy f |
根据鉴别器函数 f 将 xs 划分为集合映射 |
Element Conditions: | |
xs forall p |
判断集合中所有的元素是否都满足条件 p |
xs exists p |
判断集合中是否存在一个元素满足条件 p |
xs count p |
xs 中满足条件 p 的元素的个数 |
Folds: | |
(z /: xs) (op) |
以 z 为初始值,从左到右对 xs 中的元素执行操作为 op 的归约操作 |
(xs :\ z) (op) |
以 z 为初始值,从右到左对 xs 中的元素执行操作为 op 的归约操作 |
xs.foldLeft(z) (op) |
同 (z /: xs) (op) |
xs.foldRight(z) (op) |
同 (xs :?z) (op) |
xs reduceLeft op |
从左到右对 xs 中的元素执行操作为 op 的归约操作 |
xs reduceRight op |
从右到左对 xs 中的元素执行操作为 op 的归约操作 |
Specific Folds: | |
xs.sum |
累计求和 |
xs.product |
累计求积 |
xs.min |
xs 中的最小值 |
xs.max |
xs 中的最大值 |
String: | |
xs addString (b, start, sep, end) |
向 StringBuilder b 中添加一个字符串, 该字符串包含 xs 的所有元素。start、seq 和 end 都是可选的,seq 为分隔符,start 为开始符号,end 为结束符号。 |
xs mkString (start, seq, end) |
将集合转化为一个字符串。start、seq 和 end 都是可选的,seq 为分隔符,start 为开始符号,end 为结束符号。 |
xs.stringPrefix |
返回 xs.toString 字符串开头的集合名称 |
Views: | |
xs.view |
生成 xs 的视图 |
xs view (from, to) |
生成 xs上指定索引范围内元素的视图 |
下面为部分方法的使用示例:
scala> List(1, 2, 3, 4, 5, 6).collect case i if i % 2 == 0 => i * 10
res0: List[Int] = List(20, 40, 60)
scala> List(1, 2, 3, 4, 5, 6).withFilter(_ % 2 == 0).map(_ * 10)
res1: List[Int] = List(20, 40, 60)
scala> (10 /: List(1, 2, 3)) (_ + _)
res2: Int = 16
scala> List(1, 2, 3, -4, 5) takeWhile (_ > 0)
res3: List[Int] = List(1, 2, 3)
scala> List(1, 2, 3, -4, 5) span (_ > 0)
res4: (List[Int], List[Int]) = (List(1, 2, 3),List(-4, 5))
scala> List(1, 2, 3).mkString("[","-","]")
res5: String = [1-2-3]
四、Trait Iterable
Scala中所有的集合都直接或者间接实现了Iterable
特质,Iterable
拓展自Traversable
,并额外定义了部分方法:
方法 | 作用 |
---|---|
Abstract Method: | |
xs.iterator |
返回一个迭代器,用于遍历 xs 中的元素, 与foreach遍历元素的顺序相同。 |
Other Iterators: | |
xs grouped size |
返回一个固定大小的迭代器 |
xs sliding size |
返回一个固定大小的滑动窗口的迭代器 |
Subcollections: | |
xs takeRigtht n |
返回 xs 中最后 n 个元素组成的集合(如果无序,则返回任意 n 个元素组成的集合) |
xs dropRight n |
返回 xs 中除了最后 n 个元素外的部分 |
Zippers: | |
xs zip ys |
返回 xs 和 ys 的对应位置上的元素对组成的集合 |
xs zipAll (ys, x, y) |
返回 xs 和 ys 的对应位置上的元素对组成的集合。其中较短的序列通过附加元素 x 或 y 来扩展以匹配较长的序列。 |
xs.zipWithIndex |
返回一个由 xs 中元素及其索引所组成的元素对的集合 |
Comparison: | |
xs sameElements ys |
测试 xs 和 ys 是否包含相同顺序的相同元素 |
所有方法的使用示例如下:
scala> List(1, 2, 3).iterator.reduce(_ * _ * 10)
res0: Int = 600
scala> List("a","b","c","d","e") grouped 2 foreach println
List(a, b)
List(c, d)
List(e)
scala> List("a","b","c","d","e") sliding 2 foreach println
List(a, b)
List(b, c)
List(c, d)
List(d, e)
scala> List("a","b","c","d","e").takeRight(3)
res1: List[String] = List(c, d, e)
scala> List("a","b","c","d","e").dropRight(3)
res2: List[String] = List(a, b)
scala> List("a","b","c").zip(List(1,2,3))
res3: List[(String, Int)] = List((a,1), (b,2), (c,3))
scala> List("a","b","c","d").zipAll(List(1,2,3),"",4)
res4: List[(String, Int)] = List((a,1), (b,2), (c,3), (d,4))
scala> List("a","b","c").zipAll(List(1,2,3,4),"d","")
res5: List[(String, Any)] = List((a,1), (b,2), (c,3), (d,4))
scala> List("a", "b", "c").zipWithIndex
res6: List[(String, Int)] = List((a,0), (b,1), (c,2))
scala> List("a", "b") sameElements List("a", "b")
res7: Boolean = true
scala> List("a", "b") sameElements List("b", "a")
res8: Boolean = false
五、修改集合
当你想对集合添加或者删除元素,需要根据不同的集合类型选择不同的操作符号:
操作符 | 描述 | 集合类型 |
---|---|---|
coll(k) 即coll.apply(k) |
获取指定位置的元素 | Seq, Map |
coll :+ elem elem +: coll |
向集合末尾或者集合头增加元素 | Seq |
coll + elem coll + (e1, e2, ...) |
追加元素 | Seq, Map |
coll - elem coll - (e1, e2, ...) |
删除元素 | Set, Map, ArrayBuffer |
coll ++ coll2 coll2 ++: coll |
合并集合 | Iterable |
coll -- coll2 | 移除coll中包含的coll2中的元素 | Set, Map, ArrayBuffer |
elem :: lst lst2 :: lst |
把指定列表(lst2)或者元素(elem)添加到列表(lst)头部 | List |
list ::: list2 | 合并List | List |
set | set2 set & set2 set &~ set2 |
并集、交集、差集 | Set |
coll += elem coll += (e1, e2, ...) coll ++= coll2 coll -= elem coll -= (e1, e2, ...) coll --= coll2 |
添加或者删除元素,并将修改后的结果赋值给集合本身 | 可变集合 |
elem +=: coll coll2 ++=: coll |
在集合头部追加元素或集合 | ArrayBuffer |
参考资料
- https://docs.scala-lang.org/overviews/collections/overview.html
- https://docs.scala-lang.org/overviews/collections/trait-traversable.html
- https://docs.scala-lang.org/overviews/collections/trait-iterable.html
更多大数据系列文章可以参见个人 GitHub 开源项目: 程序员大数据入门指南
以上是关于scala集合的主要内容,如果未能解决你的问题,请参考以下文章