6 数据结构
在scala 编程中经常需要用到各种数据结构,比如数组(Array)、元组(Tuple)、列表(List)、映射(Map)、集合(Set)等。
Scala同时支持可变集合和不可变集合,不可变集合从不可变,可以安全的并发访问;
不可变集合:scala.collection.immutable
可变集合: scala.collection.mutable
Scala优先采用不可变集合,对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本;
不可变集合层次结构:
可变集合层次结构:
6.1 数组
数组是一种可变的、可索引的、元素具有相同类型的数据集合;
分为定长和变长的,也就是可以改变长度和固定长度的(同样 集合、映射、元组也分为定长和变长);
定长不用引用第3方的包,变长需要引用;
1)定长数组
// 在Array的object对象中有apply方法(就是创建对象的),不需要new关键字了
scala> val arr = Array[Int](1,2,3)
arr: Array[Int] = Array(1, 2, 3)
// 获取数组长度
scala> arr.size
res32: Int = 3
// 获取数组元素, 下标从0开始,用()括起来
scala> arr(0)
res33: Int = 1
// 不可变数组可以修改元素
scala> arr(0) = 10
scala> println(arr)
[I@49825659
// 通过toBUffer来看到内部数据
scala> println(arr.toBuffer)
ArrayBuffer(10, 2, 3)
// 数组内部存储的类型是一致的,如果不一致,就找公共的类型
scala> val arr = Array(1,"aa",Array[Int](1,2,3))
arr: Array[Any] = Array(1, aa, Array(1, 2, 3))
scala> arr(2)
res37: Any = Array(1, 2, 3)
scala> arr(2)(1)
<console>:13: error: Any does not take parameters
arr(2)(1)
^
// Any类型什么也干不了,需要强转成指定类型
scala> res37.asInstanceOf[Array[Int]]
res39: Array[Int] = Array(1, 2, 3)
scala> res39(1)
res40: Int = 2
scala> val arr = Array[Int](1,4,2,5,6,7)
arr: Array[Int] = Array(1, 4, 2, 5, 6, 7)
// 升序排序
scala> arr.sorted
res41: Array[Int] = Array(1, 2, 4, 5, 6, 7)
// 降序排序
scala> arr.sorted.reverse
res42: Array[Int] = Array(7, 6, 5, 4, 2, 1)
// 聚合函数
scala> arr.sum
res43: Int = 25
scala> arr.max
res45: Int = 7
scala> arr.min
res46: Int = 1
// 数组元素遍历
scala> for(i <- arr) print(s"${i} ")
1 4 2 5 6 7
scala>
// 数组下标方式遍历
scala> for(i <- 0 until arr.size) print(s"${arr(i)} ")
1 4 2 5 6 7
scala> arr.size
res49: Int = 6
scala> arr.length
res50: Int = 6
// 数组和yield产生新数组
scala> for(i <- arr) yield i * 10
res51: Array[Int] = Array(10, 40, 20, 50, 60, 70)
注意:
设置带初始值的定长数组不能用new,因为是调用Array的静态对象,这个静态对象可以传递多个参数,而new的是调用类的构造方法只能接受一个参数就是数组的长度
2)变长数组
不能直接使用,需要引用ArrayBuffer这个类,不引入就找不到这个类
scala> val arr = new ArrayBuffer[Int]
<console>:11: error: not found: type ArrayBuffer
val arr = new ArrayBuffer[Int]
^
// 变长数组需要手动引入
scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBuffer
scala> val arr = new ArrayBuffer[Int]
arr: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
// 后面追加
scala> arr.append(-1)
// 指定下标插入
scala> arr.insert(0,-2)
scala> println(arr)
ArrayBuffer(-2, -1)
// + 用来加元素和元组
scala> arr += 1
res55: arr.type = ArrayBuffer(-2, -1, 1)
scala> arr += (2,3)
res56: arr.type = ArrayBuffer(-2, -1, 1, 2, 3)
// ++ 用来++同类(序列)
scala> arr ++= Array[Int](4,5)
res57: arr.type = ArrayBuffer(-2, -1, 1, 2, 3, 4, 5)
scala> arr ++= ArrayBuffer[Int](6,7)
res58: arr.type = ArrayBuffer(-2, -1, 1, 2, 3, 4, 5, 6, 7)
// -- 用来--同类(序列)
scala> arr --= ArrayBuffer[Int](6,7)
res59: arr.type = ArrayBuffer(-2, -1, 1, 2, 3, 4, 5)
scala> arr --= Array[Int](4,5)
res60: arr.type = ArrayBuffer(-2, -1, 1, 2, 3)
// - 用来-元素或元组
scala> arr -= (2,3)
res61: arr.type = ArrayBuffer(-2, -1, 1)
scala> arr -= 1
res62: arr.type = ArrayBuffer(-2, -1)
// remove 减下标并能获取到下标对应的元素
scala> arr.remove(0)
res63: Int = -2
scala> println(arr)
ArrayBuffer(-1)
3)定长数组与变长数组的相互转换
scala> val arr = Array[Int](1,2,3)
arr: Array[Int] = Array(1, 2, 3)
// Array ---> ArrayBuffer
scala> arr.toBuffer
res65: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3)
// ArrayBuffer ---> Array
scala> res65.toArray
res66: Array[Int] = Array(1, 2, 3)
6.2 元组
scala 的元组是对多个不同类型对象的一种简单封装。Scala 提供了TupleN 类(N的范围为1 ~ 22),用于创建一个包含N个元素的元组。
构造元组只需把多个元素用逗号隔开并用圆括号括起来。
元组取值时,元组的下标是从1开始的,而数组的下标是从0开始的,要注意区别;
// 元组的每个元素都可以看到具体的类型
scala> val t1 = (1, "hainiu", Array[Int](1,2,3), (4,5))
t1: (Int, String, Array[Int], (Int, Int)) = (1,hainiu,Array(1, 2, 3),(4,5))
// 元组用 t1._N, N从1开始
scala> t1._2
res15: String = hainiu
scala> t1._3(1)
res16: Int = 2
scala> t1._4._2
res17: Int = 5
// 元组元素不可修改
scala> t1._1 = 10
<console>:12: error: reassignment to val
t1._1 = 10
6.3 列表
1)不可变列表
不可变列表:元素和长度都不可变
// 不可变列表:元素和长度都不可变
scala> val list = List[Int](1,2,3)
list: List[Int] = List(1, 2, 3)
scala> list(1)
res19: Int = 2
// 元素不可变
scala> list(1) = 10
<console>:13: error: value update is not a member of List[Int]
list(1) = 10
^
scala> list.size
res21: Int = 3
但可以产生新的列表
scala> val list2 = List(1,2,3)
list2: List[Int] = List(1, 2, 3)
// 在list2 前面加 0 ---> List(0, 1, 2, 3)
scala> list2.::(0)
scala> list2.+:(0)
scala> 0 :: list2
scala> 0 +: list2
// 在list2 后面加 0 ---> List(1, 2, 3, 0)
scala> list2.:+(0)
scala> list2 :+ 0
// 合并两个list并生成新的list
scala> list2 ::: List(2,3,4)
res29: List[Int] = List(1, 2, 3, 2, 3, 4)
scala> list2 ++ List(2,3,4)
res30: List[Int] = List(1, 2, 3, 2, 3, 4)
// Nil 代表空列表
scala> Nil
res31: scala.collection.immutable.Nil.type = List()
scala> 0 :: 1 :: Nil
res32: List[Int] = List(0, 1)
2)可变列表
// 需要主动引入可变列表
scala> import scala.collection.mutable.ListBuffer
import scala.collection.mutable.ListBuffer
scala> val list = new ListBuffer[Int]
list: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
// 添加元素
scala> list.append(1)
// 在指定位置插入
scala> list.insert(0, -1)
// + 用来加元素和元组
scala> list += 2
res15: list.type = ListBuffer(-1, 1, 2)
scala> list += (3,4)
res16: list.type = ListBuffer(-1, 1, 2, 3, 4)
// ++ 用来++同类(序列)
scala> list ++= Array(5,6)
res17: list.type = ListBuffer(-1, 1, 2, 3, 4, 5, 6)
scala> list ++= List(7,8)
res18: list.type = ListBuffer(-1, 1, 2, 3, 4, 5, 6, 7, 8)
// 删除元素, 减下标元素
scala> list.remove(0)
res19: Int = -1
scala> list.size
res20: Int = 8
// -- 用来--同类(序列)
scala> list --= List(7,8)
res21: list.type = ListBuffer(1, 2, 3, 4, 5, 6)
scala> list --= Array(5,6)
res22: list.type = ListBuffer(1, 2, 3, 4)
// - 用来减元素和元组
scala> list -= (1,2)
res23: list.type = ListBuffer(3, 4)
scala> list -= 3
res24: list.type = ListBuffer(4)
注意:在可变list上也可以调用不可变list的"::","+:",":+","++",":::",区别是可变list返回的是新的ListBuffer,不可变list返回的是新的List
:: 在列表前面添加 【ListBuffer 不可用】
+: 在列表前面添加
:+ 在列表后面添加
++ 两个列表拼接
::: 两个列表拼接 【ListBuffer 不可用】
scala> val list = ListBuffer(1,2,3)
list: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)
// :: ::: 在可变列表中用不了
scala> 0 :: list
<console>:14: error: value :: is not a member of scala.collection.mutable.ListBuffer[Int]
0 :: list
^
scala> 0 +: list
res27: scala.collection.mutable.ListBuffer[Int] = ListBuffer(0, 1, 2, 3)
scala> list :+ 0
res28: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 0)
scala> list ++ List(4,5)
res29: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 4, 5)
scala> list ::: List(4,5)
<console>:14: error: type mismatch;
found : scala.collection.mutable.ListBuffer[Int]
required: List[?]
list ::: List(4,5)
^
3)ListBuffer 、 List、ArrayBuffer、Array的转换
6.4 集合
特性:去重
1)不可变set
scala> val set = Set(1,2,3)
set: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
scala> set.size
res36: Int = 3
// 获取第一个元素
scala> set.head
res37: Int = 1
// 获取除了第一个元素以外的其他元素组成的set
scala> set.tail
res38: scala.collection.immutable.Set[Int] = Set(2, 3)
// 判断集合是否为空
scala> set.isEmpty
res40: Boolean = false
// 使用不可变的HashSet,需要引入不可变HashSet
scala> val set = HashSet(1,2,3)
<console>:12: error: not found: value HashSet
val set = HashSet(1,2,3)
^
scala> import scala.collection.immutable.HashSet
import scala.collection.immutable.HashSet
scala> val set = HashSet(1,2,3)
set: scala.collection.immutable.HashSet[Int] = Set(1, 2, 3)
scala> set.size
res41: Int = 3
// 不可变set可以产生新的set集合
scala> set + 1
res42: scala.collection.immutable.HashSet[Int] = Set(1, 2, 3)
scala> set + 4
res43: scala.collection.immutable.HashSet[Int] = Set(1, 2, 3, 4)
scala> set ++ Set(3,5)
res44: scala.collection.immutable.HashSet[Int] = Set(5, 1, 2, 3)
2)可变set
// 引入不可变HashSet
scala> import scala.collection.immutable.HashSet
import scala.collection.immutable.HashSet
scala> val set = HashSet(1,2,3)
set: scala.collection.immutable.HashSet[Int] = Set(1, 2, 3)
// 引入可变HashSet
scala> import scala.collection.mutable.HashSet
import scala.collection.mutable.HashSet
// 报错原因是当前有两个HashSet, 创建对象不知道用哪个
scala> val set = new HashSet[Int]
<console>:14: error: reference to HashSet is ambiguous;
it is imported twice in the same scope by
import scala.collection.mutable.HashSet
and import scala.collection.immutable.HashSet
val set = new HashSet[Int]
^
// 冲突了,起别名,用别名来创建对象
scala> import scala.collection.mutable.{HashSet => HashSetMu}
import scala.collection.mutable.{HashSet=>HashSetMu}
scala> val set = new HashSetMu[Int]
set: scala.collection.mutable.HashSet[Int] = Set()
// 可变集合的添加
scala> set.add(1)
res45: Boolean = true
scala> set.add(1)
res46: Boolean = false
scala> set += 2
res47: set.type = Set(1, 2)
scala> set += (3,4)
res48: set.type = Set(1, 2, 3, 4)
scala> set ++= Set(4,5)
res49: set.type = Set(1, 5, 2, 3, 4)
scala> println(set)
Set(1, 5, 2, 3, 4)
// 因为set不按照下标取遍历, remove减的是元素
scala> set.remove(5)
res51: Boolean = true
scala> set -= 1
res52: set.type = Set(2, 3, 4)
scala> set -= (2,3)
res53: set.type = Set(4)
scala> set --= Set(4)
res54: set.type = Set()
scala> set.isEmpty
res55: Boolean = true
6.5 映射
映射也就是一个hash表,相当于java里的map
1)不可变map
// 创建不可变map对象
// kv键值对:可以用 k -> v 表示, 也可以用 (k, v) 表示
scala> val map = Map("a"->1, "b"->(1,2), ("c",3))
map: scala.collection.immutable.Map[String,Any] = Map(a -> 1, b -> (1,2), c -> 3)
scala> map.size
res0: Int = 3
// 获取key对应的value
scala> map("a")
res1: Any = 1
// 强转
scala> res0.asInstanceOf[Int]
res2: Int = 1
// 不可变map不能修改元素
scala> map("a") = 10
<console>:13: error: value update is not a member of scala.collection.immutable.Map[String,Any]
map("a") = 10
^
// 获取时如果key不存在,抛异常
scala> map("d")
java.util.NoSuchElementException: key not found: d
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:59)
at scala.collection.MapLike$class.apply(MapLike.scala:141)
at scala.collection.AbstractMap.apply(Map.scala:59)
... 32 elided
// 解决方案1: 通过get方法,获取Option对象
// Option 对象有两个子类:
// None:代表没数据
// Some: 代表有数据, 可通过get() 提取Some对象里的数据
scala> map.get("d")
res5: Option[Any] = None
// 获取对应的Option对象
scala> map.get("a")
res6: Option[Any] = Some(1)
// 提取数据
scala> res6.get
res7: Any = 1
// 解决方案2:通过getOrElse方法,如果key不存在,将设置的默认值返回
scala> map.getOrElse("d", "default value")
res8: Any = default value
不可变 Map 内部元素不可变,但可以产生新的Map
scala> val map = Map("a"->1)
map: scala.collection.immutable.Map[String,Int] = Map(a -> 1)
scala> map + ("b"-> 2)
res9: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)
scala> map + (("c", 3))
res10: scala.collection.immutable.Map[String,Int] = Map(a -> 1, c -> 3)
scala> map ++ Map("d"-> 4)
res11: scala.collection.immutable.Map[String,Int] = Map(a -> 1, d -> 4)
scala> res9 - "b"
res12: scala.collection.immutable.Map[String,Int] = Map(a -> 1)
scala> res11 - ("d")
res13: scala.collection.immutable.Map[String,Int] = Map(a -> 1)
2)可变map
添加删除数据
// 引入可变的HashMap
scala> import scala.collection.mutable.HashMap
import scala.collection.mutable.HashMap
scala> val map = new HashMap[String,Int]
map: scala.collection.mutable.HashMap[String,Int] = Map()
// 添加数据
scala> map.put("a",1)
res69: Option[Int] = None
scala> println(map)
Map(a -> 1)
scala> map += ("b"-> 2)
res71: map.type = Map(b -> 2, a -> 1)
scala> map += (("c", 3))
res72: map.type = Map(b -> 2, a -> 1, c -> 3)
scala> map ++= Map("d"-> 4)
res73: map.type = Map(b -> 2, d -> 4, a -> 1, c -> 3)
// 删除数据
scala> map.remove("a")
res74: Option[Int] = Some(1)
scala> res74.get
res75: Int = 1
scala> map -= "b"
res76: map.type = Map(d -> 4, c -> 3)
scala> map -= ("c","d")
res77: map.type = Map()
scala> map.isEmpty
res79: Boolean = true
遍历map
// 遍历map
scala> val map = HashMap("b" -> 2, "d" -> 4, "a" -> 1, "c" -> 3)
map: scala.collection.mutable.HashMap[String,Int] = Map(b -> 2, d -> 4, a -> 1, c -> 3)
// 以keyset的方式根据key找value
scala> for(k <- map.keySet)println(s"k:${k}, v:${map(k)}")
k:b, v:2
k:d, v:4
k:a, v:1
k:c, v:3
// 直接遍历一组k,v
scala> for((k,v) <- map)println(s"k:${k}, v:${v}")
k:b, v:2
k:d, v:4
k:a, v:1
k:c, v:3
// 遍历value
scala> for(v <- map.values)println(s"v:${v}")
v:2
v:4
v:1
v:3
利用元组进行组合赋值
val re,(a,b,c,d,e,f,g) = ("a",1,1L,1.0,Array(1,2),Map(("a",1)),"b" -> 2)
toMap操作——将对偶的数组转换成map
// 对偶数组
scala> val arr1 = Array(("a",1), ("b",2))
arr1: Array[(String, Int)] = Array((a,1), (b,2))
scala> arr1.toMap
res86: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)
// 对偶列表
scala> val list = List(("a",1), ("b",2))
list: List[(String, Int)] = List((a,1), (b,2))
scala> list.toMap
res87: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)
zip操作(拉链操作),通过拉链操作得到对偶数组或列表
scala> val arr1 = Array("a", "b", "c")
arr1: Array[String] = Array(a, b, c)
scala> val arr2 = Array(1,2)
arr2: Array[Int] = Array(1, 2)
// 通过拉链得到对偶数组,如果对不齐就舍去
scala> arr1.zip(arr2)
res88: Array[(String, Int)] = Array((a,1), (b,2))
scala> arr2.zip(arr1)
res89: Array[(Int, String)] = Array((1,a), (2,b))
scala> arr1 zip arr2
res90: Array[(String, Int)] = Array((a,1), (b,2))
scala> res88.toMap
res91: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)
如何将 List(Array("a",1), Array("b",2)) 转化成 Map("a"->1, "b"-> 2)