第4章 数据结构
4.1 主要的集合特质
4.2 数组 Array
定长数组
//1.定长数组 val arr1 = new Array[Int](10) //不定义[Int] 默认为 [Nothing] println(arr1.mkString(",")) val arr2 = Array(1, 2, 3) println(arr2.mkString(",")) arr2.apply(1) //赋值 arr2(1) = 10 //等价于 arr2.update(1, 10) println(arr2.mkString(",")) //追加 val arr3 = arr1 :+ "??" val arr4 = "??" :+ arr1 println(arr3.mkString(", "))
变长数组
//2.变长数组 //小括号可以存放初始化的元素内容 val arrBuffer1 = ArrayBuffer[Int](10, 9, 8) val arrBuffer2 = ArrayBuffer[Int]() //小括号中指定的元素 println(arrBuffer1) //ArrayBuffer(10, 9, 8) 直接打印的是数组 println(arrBuffer2) //ArrayBuffer() println(arrBuffer1.mkString(",")) //10,9,8 //赋值,取值 arrBuffer1(1) = -1 println(arrBuffer1) //ArrayBuffer(10, -1, 8) println(arrBuffer1(1)) //-1 println(arrBuffer1.apply(2)) //8 //追加 arrBuffer1.append(1, 2, 3) println(arrBuffer1) //ArrayBuffer(10, -1, 8, 1, 2, 3) val arrBuffer3 = arrBuffer1 :+ 90 println(arrBuffer1) //ArrayBuffer(10, -1, 8, 1, 2, 3) println(arrBuffer3) //ArrayBuffer(10, -1, 8, 1, 2, 3, 90)
for (i <- 0 until a.length) println(i + ": " + a(i)) for (elem <- a) println(elem)
数组转换
ArrayBuffer = Array.toBuffer Array = ArrayBuffer.toArray
多维数组
val matrix = Array.ofDim[Double](3, 4)
赋值:
matrix(row)(column) = 17.29
和 Java 数组的互操作
import scala.collection.JavaConverters._ import scala.collection.mutable.ArrayBuffer val command = ArrayBuffer("ls", "-al", "/") val pb = new ProcessBuilder(command.asJava) // Scala to Java val cmd : Buffer[String] = pb.command().asScala // Java to Scala cmd == command
4.3 元组 Tuple
//元组 //创建 val tuple1 = (1, 2, 3, "hello", 4) //赋值 取值 println(tuple1._4) //tuple 的遍历 //方式一: for(e <- tuple1.productIterator){ println(e) } //方式二 tuple1.productIterator.foreach(println(_)) tuple1.productIterator.foreach(i => println("tuplel中的元素:" + i))
4.4 列表 List
//列表 List val list1 = List(1, 2) //取值 赋值 println(list1(1)) val list1_2 = list1.updated(1, 10) println(list1) //List(1, 2) //list 集合不能在原有基础上修改值 println(list1_2) //List(1, 10) //追加,另一种创建方式 val list2 = 1 :: 2 :: 3 :: Nil //Nil 表示空的list val list3 = 1 :: 2 :: 3 :: List(6, 7) //Nil 表示空的list val list4 = 1 :: 2 :: 3 :: List(6, 7) :: Nil println(list2) //List(1, 2, 3) println(list3) //List(1, 2, 3, 6, 7) println(list4) //List(1, 2, 3, List(6, 7)) println(Nil) //List() //ListBuffer val list5 = ListBuffer[Int]() list5.append(1, 2) println(list5) //ListBuffer(1, 2) list5 update(0, 10) //ListBuffer 可以在原有基础上修改值 println(list5) //ListBuffer(10, 2)
4.5 队列 Queue
//队列 val q1 = mutable.Queue[Int](1, 2) println(q1) //Queue(1, 2) val q2 = new mutable.Queue[Int]() q2 ++= q1 println(q2) //Queue(1, 2) //取值 赋值 println(q1(1)) q1(1) = 10 //2 println(q1) //Queue(1, 10) //追加元素 q1 += 20 q1 ++= List(1, 2, 3) println(q1) //Queue(1, 10, 20, 1, 2, 3) q1.enqueue(99, 98) println(q1) //Queue(1, 10, 20, 1, 2, 3, 99, 98) //删除 q1.dequeue() println(q1) //Queue(10, 20, 1, 2, 3, 99, 98) //三个常用方法 println(q1.head) println(q1.last) println(q1.tail)
4.6 映射 Map
//Map val map1 = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) //不可变 println(map1) //Map(Alice -> 10, Bob -> 3, Cindy -> 8) val map2 = mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) //可变 println(map2) //Map(Bob -> 3, Alice -> 10, Cindy -> 8) val map3 = mutable.Map(("Alice", 10), ("Bob", 3), ("Cindy", 8)) println(map3) //Map(Bob -> 3, Alice -> 10, Cindy -> 8) //取值 赋值 println(map1("Alice")) //10 println(map1.updated("Alice", 90)) //Map(Alice -> 90, Bob -> 3, Cindy -> 8) map2("Alice") = 90 //可变集合可以直接改变值,不可变集合修改需要使用updated产生新的集合 println(map1("Alice")) //10 println(map2("Alice")) //90 //赋值 追加 map2 += ("Alice" -> 80) map2 += ("AAAA" -> 10) println(map2) //Map(Bob -> 3, AAAA -> 10, Alice -> 80, Cindy -> 8) //遍历 for(m <- map2){ println(m) println(m._1) println(m._2) } /* 结果: (Bob,3) Bob 3 (AAAA,10) AAAA 10 (Alice,80) Alice 80 (Cindy,8) Cindy 8 */ for((k, v) <- map2){ println(k + ":" + v) } /* 结果: Bob:3 AAAA:10 Alice:80 Cindy:8 */ val map4 = Map("Alice" -> "AA", "Bob" -> 3, "Cindy" -> 8) //键值可以为任意类型 println(map4) //Map(Alice -> AA, Bob -> 3, Cindy -> 8) val map5 = mutable.Map[String, Int]("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) //指定泛型 println(map5) //Map(Bob -> 3, Alice -> 10, Cindy -> 8)
4.7 集 Set
//Set //创建 val set1 = Set(1, 2, 2, 3) println(set1) //Set(1, 2, 3) val set2 = mutable.Set(1, 2, 2, 3) println(set2) //Set(1, 2, 3) //取值 println(set1(1)) //true //不能通过下标访问 println(set1.contains(3)) //true //追加值 // set1 不能进行追加 set2.add(4) println(set2) //Set(1, 2, 3, 4) set2 += 5 println(set2) //Set(1, 5, 2, 3, 4) //遍历 for(s <- set2){ println(s) } /* 结果: 1 5 2 3 4 */ //删除元素 set2 -= 1 println(set2) //Set(5, 2, 3, 4) set2.remove(2) println(set2) //Set(5, 3, 4)
4.8 集合元素与函数的映射
//集合中的元素与函数之间的映射 val list11 = List("Alice", "Bob", "Kotlin") val list11_1 = list11.map(x => x.toUpperCase) println(list11_1) //List(ALICE, BOB, KOTLIN) println(list11) //List(Alice, Bob, Kotlin) //等价于 def f1(x: String) : String = { x.toUpperCase } val list1_3 = list11.map(f1) println(list1_3) List(Alice, Bob, Kotlin)
2)flatmap:flat 即压扁,压平,扁平化,效果就是将集合中的每个元素的子元素映射到某个函数并返回新的集合
val names = List("Alice", "Bob", "Nick") println(names.flatMap(_.toUpperCase())) //List(A, L, I, C, E, B, O, B, N, I, C, K)
4.9 简化、折叠、扫描
1)折叠,化简:将二元函数引用于集合中的函数
val list = List(1, 2, 3, 4, 5) val i1 = list.reduceLeft(_-_) val i2 = list.reduceRight(_-_) println(i1) println(i2)
笔记:
//化简操作 val list11_4 = list11.map(_.toLowerCase) println(list11_4) //List(alice, bob, kotlin) //下划线只能使用一次,x 可以多次使用。 val list11_5 = list11.map(x => x.toUpperCase + x.toLowerCase) println(list11_5) //List(ALICEalice, BOBbob, KOTLINkotlin) println(List(1,7,2,9).reduceLeft(_ - _)) //-17
//化简,折叠,扫描 val list12 = List(1, 2, 3, 4, 5) val list12_Left1 = list12.reduceLeft(_-_) //这里的两个下划线分别代表 result 和 x println(list12_Left1) //-13 //等价于 val list12_Left2 = list12.reduceLeft((result, x) => result - x) println(list12_Left2) //-13 val list12_Right1 = list12.reduceRight(_-_) println(list12_Right1) //3
2)折叠,化筒:fold
fold 函数将上一步返回的值作为函数的第一个参数继续传递参与运算,直到 list 中的所有元素被遍历。
可以把 reduceLeft 看作简化版的 foldLeft。相关函数:fold,foldLeft,foldRight,可以参考 reduce 的相关方法理解。
//fold val list13 = List(1, 9, 2, 8) val list13_fold1 = list13.fold(5)((sum, y) => sum + y) val list13_fold2 = list13.fold(5)((sum, y) => sum - y) println(list13_fold1) //25 println(list13_fold2) //-15 val list13_fold_right = list13.foldRight(100)((sum, y) => sum - y) println(list13_fold_right) //86
提示: foldLeft 和 foldRight 有一种缩写方法对应分别是:/: 和 :\
例如:
val list4 = List(1, 9, 2, 8) val i6 = (c /: list4)(_-_) //上一步运算的结果减下一个元素
//val i6 = (c /: list4)((res, next) => res - next) println(i6)
3)统计一句话中,各个文字出现的次数
//统计一句话中,各个文字出现的次数 val sentence = "一首现代诗《笑里藏刀》:哈哈哈哈哈哈哈哈哈哈哈哈哈哈刀哈哈哈哈哈哈哈哈哈哈哈哈" val map_1 = (mutable.Map[Char, Int]() /: sentence)((m, c) => m + (c -> (m.getOrElse(c, 0) + 1))) println(map_1) //Map(代 -> 1, 笑 -> 1, 》 -> 1, 里 -> 1, 诗 -> 1, 哈 -> 26, 刀 -> 2, 首 -> 1, 《 -> 1, : -> 1, 藏 -> 1, 一 -> 1, 现 -> 1)
4)折叠,化简,扫描
这个理解需要结合上面的知识,扫描,即对某一个集合的所有元素做 fold 操作,
但是会把产生的所有中间结果放置于一个集合中保存。
val i8 = (1 to 8).scanLeft(0)(_ + _)
println(i8) //Vector(0, 1, 3, 6, 10, 15, 21, 28, 36)
化简操作:
折叠操作:
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)) }
扫描操作:
4.10 拉链
//拉链 val zip1 = List("1893278923423", "328742917419") val zip2 = List("孙悟空", "猪八戒") val zipResultList = zip1 zip zip2 println(zipResultList) //List((1893278923423,孙悟空), (328742917419,猪八戒)) //封装到Map中 val zipMap = mutable.Map[String, String]() for(e <- zipResultList){ zipMap += e } println(zipMap) //Map(328742917419 -> 猪八戒, 1893278923423 -> 孙悟空)
4.11 迭代器
val iterator = List(1, 2, 3, 4, 5).iterator while (iter.hasNext) println(iter.next()) //或: for (elem <- iter) println(elem)
4.12 流 Stream
stream是一个集合。这个集合,可以用于存放,无穷多个元素,但是这无穷个元素并不会一次性生产出来,
而是需要用到多大的区间,就会动态的生产,末尾元素遵循lazy规则
1)使用 #:: 得到一个 stream
def numsFrom(n: BigInt) : Stream[BigInt] = n #:: numsForm(n + 1)
2)传递一个值,并打印 stream 集合
val tenOrMore = numsForm(10)
println(tenOrMore )
3)tail 的每一次使用,都会动态的向 stream 集合按照规则生成新的元素
println(tenOrMore.tail)
println(tenOrMore)
4)使用 map 映射 stream 的元素并进行一些计算
println(numsForm(5).map(x => x * x))
笔记:
//Stream def numForm(initNum: BigInt): Stream[BigInt] = { initNum #:: numForm(initNum + 1) } val numStream = numForm(0) val s1 = numStream.tail //1.生成一个排除了首个元素的新集合 2.tail方法会触发stream的使用,会在调用 tail 方法的 stream 上新增元素 println(s1) //Stream(1, ?) val s2 = s1.tail println(s1) //Stream(1, 2, ?) println(s2) //Stream(2, ?) println(numStream) //Stream(0, 1, 2, ?) println(numStream.tail) //Stream(1, 2, ?) println(numStream.tail.tail) //Stream(2, ?) println(numStream.tail.tail.tail) //Stream(3, ?) val s3 = numStream.tail val s4 = s3.tail println(s3) //Stream(1, 2, 3, ?) println(s4) //Stream(2, 3, ?)
4.13 视图 View
val view = (1L to 1000000L).view.map(x => x).filter(y => y.toString == y.toString.reverse) println(view.mkString()) for(x <- view){ print(x + ",") }
//view val view = (1L to 1000000L).view.map(x => x).filter(y => y.toString == y.toString.reverse) println(view) //SeqViewMF(...) println(view.mkString(" ")) println(view(22)) //141
4.14 线程安全的集合
所有线程安全的集合都是以 Synchronized 开头的集合,例如:
SynchronizedBuffer
SynchronizedMap
SynchronizedPriorityQueue
SynchronizedQueue
SynchronizedSet
SynchronizedStack
val scores = new scala.collection.mutable.HashMap[String,Int] with scala.collection.mutable.SynchronizedMap[String,Int]
4.15 并行集合
1. scala.collection.parallel.mutable.ParArray 2. scala.collection.parallel.mutable.ParHashMap 3. scala.collection.parallel.mutable.ParHashSet 4. 5. scala.collection.parallel.immutable.ParRange 6. scala.collection.parallel.immutable.ParHashMap 7. scala.collection.parallel.immutable.ParHashSet 8. scala.collection.parallel.immutable.ParVector
(1 to 5).foreach(println(_))
println()
(1 to 5).par.foreach(println(_))
2)查看并行集合中元素访问的线程
val result1 = (0 to 100).map{case_ => Thread.currentThread.getName}.distinct val result2 = (0 to 100).par.map{case_ => Thread.currentThread.getName}.distinct println(result1) //Vector(main)
println(result2) //ParVector(ForkJoinPool-1-worker-13, ForkJoinPool-1-worker-7, ForkJoinPool-1-worker-5, ForkJoinPool-1-worker-3, ForkJoinPool-1-worker-1, ForkJoinPool-1-worker-11, ForkJoinPool-1-worker-9)
4.26 操作符概述
val `val` = 42