这一节主要介绍Scala中的数据结构:
- Seq
- Set
- Map
集合特质
scala同时支持可变集合和不可变集合,不可变集合从不可变,可以安全的访问
两个主要的包
- 不可变集合:scala.collection.immutable
- 可变集合 :scala.collection,mutable
scala优先采用不可变集合,集合主要分为三大类:序列(seq),集(set),映射(map)
- seq 是一个有先后次序的值得序列,IndexedSeq能够通过整形下标快速得访问元素
- Set是一个没有先后次序得值集合,在SortedSort中,元素以某种形式排过序的顺序被访问。
- Map是一组键值对偶,Sorted按照键的排序访问其中的实体
每个Scala集合特质或者类都带有一个Apply方法的伴生对象(类似于静态方法),这个apply方法可以用来构建该集合中的实体,这是统一创建原则.
Seq
数组Array
下面的命令在命令行进入scala测试:
// 定长数组
val nums = new Array[Int](10)
val s = Array("Hello", "World")
s(0) = "Goodbye"
s
// 变长 数组缓冲
import scala.collection.mutable.ArrayBuffer
val b = ArrayBuffer[Int]()
val b2 = new ArrayBuffer[Int] // If you use new, the () is optional
b += 1
b += (1, 2, 3, 5)
b ++= Array(8, 13, 21)
// 删除最后5个元素
b.trimEnd(5)
b
// 在第三个位置插入6
b.insert(2, 6)
b
// 在第三个位置插入 7、8、9
b.insert(2, 7, 8, 9)
b
// 删除第三个元素
b.remove(2)
b
// 删除从第三个位置开始的3个元素
b.remove(2, 3)
b
// 变长数组与不变数组之间的转换
val a1 = b.toArray
a1.toBuffer
// 数组遍历
val a = Array(1, 1, 2, 3, 5, 8, 13, 21, 34, 55)
// 下标访问
for (i <- 0 until a.length)
println(i + ": " + a(i))
// 产生一个Range
0 until a.length
// 产生一个Range,以2为间隔
0 until (a.length, 2)
// Range倒转
(0 until a.length).reverse
// a 遍历
for (elem <- a)
println(elem)
// a 索引
for (i <- a.indices)
println(i + ": " + a(i))
多维数组
// 多维数组 3行4列
val matrix = Array.ofDim[Double](3, 4) // An array of arrays
val row = 0
val column = 2
matrix(0)(2) = 17.29
matrix.length
matrix(row) // An array
matrix(row).length
val triangle = new Array[Array[Int]](10)
for (i <- triangle.indices)
triangle(i) = new Array[Int](i + 1)
triangle(0)(0) = 1
for (i <- 1 until triangle.length) {
triangle(i)(0) = 1
triangle(i)(i) = 1
for (j <- 1 until triangle(i).length - 1)
triangle(i)(j) = triangle(i - 1)(j - 1) + triangle(i - 1)(j)
}
for (row <- triangle) {
for (elem <- row) print(elem + " ")
println()
}
与Java操作
// 和Java的互操作
import scala.collection.JavaConverters._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
val command = ArrayBuffer("ls", "-al", "/")
// ProessBuilder是java方法
val pb = new ProcessBuilder(command.asJava) // Scala to Java
val cmd : mutable.Buffer[String] = pb.command().asScala // Java to Scala
cmd == command
映射(Map)
映射就是key-value的集合,类似于Java中的Map
- 注意:不可变映射也可以调用方法,只不过产生新的映射,新的映射和老的映射共享大部分结构,可变映射是在原映射的基础上进行修改.
// 不可变构造映射
val scores = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
// 可变映射
val scores1 = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
// 空映射
val scores2 = new scala.collection.mutable.HashMap[String, Int]
// 对偶
"Alice" -> 10
// 对偶元组
val scores3 = Map(("Alice", 10), ("Bob", 3), ("Cindy", 8))
// 获取值
val bobsScore = scores("Bob")
// contains检测
val fredsScore = if (scores.contains("Fred")) scores("Fred") else 0
// 可以用getOrElse替换检测
scores.getOrElse("Bob", 0)
// 显示调用get,获得Option Some None
scores.get("Bob")//获取的是 Option[Int] = Some(1)
scores.get("Bob").get//获取对应的值 value
scores.get("Fred") //获取到的是Option[Int] = None
// 设置值
scores1("Bob")= 11
scores1("Fred2")=7
scores1
scores1 += ("Bob" -> 10, "Fred" -> 7)
scores1 -= "Alice"
// 不可变映射不能修改,但能够产生新映射
val newScores = scores + ("Bob" -> 10, "Fred" -> 7) // New map with update
// 遍历
for ((k, v) <- map5) println(k + " is mapped to " + v)
// Key的Set集合
scores.keySet
// 遍历value
for (v <- scores.values) println(v)
// 产生新的Map
for ((k, v) <- scores) yield (v, k)
// 排序
val scores4 = scala.collection.immutable.SortedMap("Alice" -> 10,
"Fred" -> 7, "Bob" -> 3, "Cindy" -> 8)
// 双向链表HashMap
val months = scala.collection.mutable.LinkedHashMap("January" -> 1,
"February" -> 2, "March" -> 3, "April" -> 4, "May" -> 5,
"June" -> 6, "July" -> 7, "August" -> 8, "September" -> 9,
"October" -> 10, "November" -> 11, "December" -> 12)
元组(tuple)
元组是不同类型的值的聚集
注意:
- 元组是从1开始的,可以把t1._2 改写成 t _2(必须有空格);
- 元组可以用于函数需要返回不止一个值的情况;
- 使用元组的原因之一是把多个值绑在自已,以便于他们可以一起被处理
// 元组操作
(1, 3.14, "Fred")
val t = (1, 3.14, "Fred")
val second = t._2
val first = t _1
//变量赋值
val (first1, second1, third) = t
val (first2, second2, _) = t
// 拉链操作
val symbols = Array("zhangsan", "lisi", "wangwu")
val counts = Array(2, 10, 2)
val pairs = symbols.zip(counts)
for ((s, n) <- pairs) print(s * n)
symbols.zip(counts).toMap
队列Queue
队列是先进先出的
val q1 = new scala.collection.mutable.Queue[Int]
//追加元素
q1 += 1
q1 += 2
//追加多个元素并返回队列
q1 ++= List(3, 4)
//返回并从队列删除第一个元素
q1.dequeue()
//追加多个元素,返回类型为Unit
q1.enqueue(5, 6, 7)
q1
//队列首部
q1.head
//队列尾部
q1.tail
堆栈Stack
堆栈是先进后出的
val s = new scala.collection.mutable.Stack[Int]()
//入栈
s.push(1)
//入栈多个元素
s.push(2, 3, 4)
//出栈
s.pop()
s
s.push(5)
//取栈顶元素而不出栈
s.top
s
List
- 不可变序列
在Scala中列表要么为空(Nil表示空列表) 要么是一个head元素加上一个tail列表。 - 9 :: List(5, 2) :: 操作符是将给定的头和尾创建一个新的列表
注意::: 操作符是右结合的,如9 :: 5 :: 2 :: Nil相当于 9 :: (5 :: (2 :: Nil))
list常用的操作符:
- +: (elem: A): List[A] 在列表的头部添加一个元素
- :: (x: A): List[A] 在列表的头部添加一个元素
- :+ (elem: A): List[A] 在列表的尾部添加一个元素
- ++[B](that: GenTraversableOnce[B]): List[B] 从列表的尾部添加另外一个列表
- ::: (prefix: List[A]): List[A] 在列表的头部添加另外一个列表
- val left = List(1,2,3)
- val right = List(4,5,6)
- //以下操作等价
- left ++ right // 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) //List(0,1,2,3)
不可变集合
object MuList{
//做命令行输入
def main(args: Array[String]): Unit = {
//创建一个比可变的集合
val list1 = List (1,2,3)
//另一种定义方式
val list2 = 1 :: 2 :: 3 :: Nil
//获取头部元素
val first = list1.head
//获取头部意外的其他元素,如果只有一个元素就会获得nil
val tail = list1.tail
println(list2.head + "----" + list2.tail)
//将0插入到list1前面生成一个新的list
val list3 = 0 :: list1 //添加到头部
val list4 = list1.:: (0) //添加到头部
val list5 = 0 +: list1 //添加到头部
val list6 = list1.+:(0) //添加到头部
//将一个元素添加到list的尾部
val list7 = list1 :+ 9
val list0 = List(4,5,6)
//将两个list合并成一个新的list
val list8 = list0 ++ list1
//将list1 放到list0前面
val list9 = list0 ++: list1
val list10 = list1.:::(list0)
}
}
可变长的集合
//构建一个可变列表,初始有3个元素1,2,3
val lst0 = ListBuffer[Int](1,2,3)
//创建一个空的可变列表
val lst1 = new ListBuffer[Int]
//向lst1中追加元素,注意:没有生成新的集合
lst1 += 4
lst1.append(5)
//将lst1中的元素最近到lst0中, 注意:没有生成新的集合
lst0 ++= lst1
//将lst0和lst1合并成一个新的ListBuffer 注意:生成了一个集合
val lst2= lst0 ++ lst1
//将元素追加到lst0的后面生成一个新的集合
val lst3 = lst0 :+ 5
//删除元素,注意:没有生成新的集合
val lst4 = ListBuffer[Int](1,2,3,4,5)
lst4 -= 5
//删除一个集合列表,生成了一个新的集合
val lst5=lst4--List(1,2)
//把可变list 转换成不可变的list 直接加上toList
val lst6=lst5.toList
//把可变list 转变数组用toArray
val lst7=lst5.toArray
Set
Set代表一个没有重复元素的集合;将重复元素加入Set是没有用的,而且 Set 是不保证插入顺序的,即 Set 中的元素是乱序的。
定义:val set=Set(元素,元素,…)
不可变Set
//定义一个不可变的Set集合
scala> val set =Set(1,2,3,4,5,6,7)
set: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 7, 3, 4)
//元素个数
scala> set.size
res0: Int = 7
//取集合最小值
scala> set.min
res1: Int = 1
//取集合最大值
scala> set.max
res2: Int = 7
//将元素和set1合并生成一个新的set,原有set不变
scala> set + 8
res3: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 7, 3, 8, 4)
scala> val set1=Set(7,8,9)
set1: scala.collection.immutable.Set[Int] = Set(7, 8, 9)
//两个集合的交集
scala> set & set1
res4: scala.collection.immutable.Set[Int] = Set(7)
//两个集合的并集
scala> set ++ set1
res5: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 9, 2, 7, 3, 8, 4)
//在第一个set基础上去掉第二个set中存在的元素
scala> set -- set1
res6: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 3, 4)
//返回第一个不同于第二个set的元素集合
scala> set &~ set1
res7: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 3, 4)
//计算符合条件的元素个数
scala> set.count(_ >5)
res8: Int = 2
/返回第一个不同于第二个的元素集合。&~
scala> set.diff(set1)
res9: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 3, 4)
/返回第一个不同于第二个的元素集合
scala> set1.diff(set)
res10: scala.collection.immutable.Set[Int] = Set(8, 9)
//取子set(2,5为元素位置, 从0开始,包含头不包含尾)
scala> set.slice(2,5)
res11: scala.collection.immutable.Set[Int] = Set(6, 2, 7)
//迭代所有的子set,取指定的个数组合
scala> set1.subsets(2).foreach(x=>println(x))
Set(7, 8)
Set(7, 9)
Set(8, 9)
可变长的set
//导入包
scala> import scala.collection.mutable
import scala.collection.mutable
//定义一个可变的Set
scala> val set1=new HashSet[Int]()
set1: scala.collection.mutable.HashSet[Int] = Set()
//添加元素
scala> set1 += 1
res1: set1.type = Set(1)
//添加元素 add等价于+=
scala> set1.add(2)
res2: Boolean = true
scala> set1
res3: scala.collection.mutable.HashSet[Int] = Set(1, 2)
//向集合中添加元素集合
scala> set1 ++=Set(1,4,5)
res5: set1.type = Set(1, 5, 2, 4)
//删除一个元素
scala> set1 -=5
res6: set1.type = Set(1, 2, 4)
//删除一个元素
scala> set1.remove(1)
res7: Boolean = true
scala> set1
res8: scala.collection.mutable.HashSet[Int] = Set(2, 4)
将函数映射到集合
将一元函数应用于集合中的每一个元素
map应用于集合中的每一个元素,并产生转换后的新元素
flatmap同样应用于集合的每一个元素,对于每一个元素产出一个集合,并将集合中的元素串接起来
// map 映射
names.map(_.toUpperCase) // List("PETER", "PAUL", "MARY")
for (n <- names) yield n.toUpperCase
def ulcase(s: String) = Vector(s.toUpperCase(), s.toLowerCase())
names.map(ulcase)
// flatmap映射
names.flatMap(ulcase)
names.foreach(println)
折叠简化和扫描操作
// 部分化简操作
List(1, 7, 2, 9).reduceLeft(_ - _)
List(1, 7, 2, 9).reduceRight(_ - _)
// 折叠操作
List(1, 7, 2, 9).foldLeft(0)(_ - _)
// 可以用一下方式来表示 foldLeft
(0 /: List(1, 7, 2, 9))(_ - _)
val freq = scala.collection.mutable.Map[Char, Int]()
for (c <- "Mississippi") freq(c) = freq.getOrElse(c, 0) + 1
(Map[Char, Int]() /: "Mississippi") {
(m, c) => m + (c -> (m.getOrElse(c, 0) + 1))
}
// 扫描操作
(1 to 10).scanLeft(0)(_ + _)