Scala
集合
字符串
-
Scala中字符串同样分为可变字符串和不可变字符串,不可变字符串使用
String
来定义,可变字符串使用的是StringBuilder
来定义package com.fesco.string object StringDemo { def main(args: Array[String]): Unit = { // 可变字符串 // Scala中既然将字符串看作是集合中的成员,那么字符串其实就是字符的集合 val str: StringBuilder = new StringBuilder("abc") str += 'a' println(str) // 产生一个新的字符串 val r1 = str.+("abc") println(str) println(r1) // 将结果转化为一个ArrayBuffer返回 val r2 = str.:+('c') println(str) println(r2) str.++=("abc") println(str) } }
序列(Seq
)
-
数组、列表、字符串都属于序列的子类
-
序列分为可变序列和不可变序列。不可变序列分为两大类:
IndexedSeq
:索引序列,支持通过索引来快速定位元素的位置,包含String
、Array
、Vector
、Range
等LinearSeq
:线性序列,除了支持索引的功能以外,还有头和尾的概念,包含List
、Queue
、Stack
等
-
a to b
还是a until b
返回就是一个Range对象// a to b 本质上就是返回了一个Range集合 // for (i <- 1 to 10) println(i) // 实际上底层是 val range = Range(1, 10) for (i <- range) println(i)
-
Seq
本身是一个特质,无法直接构建对象,同时伴生对象中也没有提供用于获取Seq
对象的方法 -
Seq的基本操作
-
索引和长度
package com.fesco.seq object SeqDemo { def main(args: Array[String]): Unit = { val list = List[Int](2, 4, 1, 5, 7) val arr = Array[Int](3, 5, 4, 1, 8, 0) // 通过指定下标来获取元素 println(list(2)) // 获取长度/元素个数 println(list.length) println(list.size) println(arr.size) // 索引范围 // 0 ~ list.length-1 val indices: Range = list.indices println(indices) // 遍历序列 for (i <- list.indices) println(list(i)) // isDefinedAt:判断下标是否在indices范围内 println(list.isDefinedAt(3)) // 等价于 println(3 < list.length && 3 > 0) // a lengthCompare b:a的长度大于b,返回1;a的长度小于b返回-1;a的长度等于b,返回0 println(list.lengthCompare(arr)) println(list.length == arr.length) } }
-
索引搜索
package com.fesco.seq object SeqDemo2 { def main(args: Array[String]): Unit = { val list = List[Int](3, 2, 1, 5, 7, 5, 4, 9, 8) // indexOf:获取指定元素在序列中第一次出现的下标 println(list.indexOf(5)) // lastIndexOf:获取指定元素在序列中最后一次出现的下标 println(list.lastIndexOf(5)) // indexOfSlice:子序列在序列中第一次出现的下标 val sub = List[Int](4, 9) println(list.indexOfSlice(sub)) // lastIndexOfSlice:子序列在序列中最后一次出现的下标 println(list.lastIndexOfSlice(sub)) // indexWhere:指定条件,获取满足条件的第一个元素出现的下标 // 在序列中,大于5的元素第一次出现的下标 // 默认从第0为开始寻找 // list.indexWhere(x => x > 5) println(list.indexWhere(_ > 5)) // 从指定下标开始向后寻找 println(list.indexWhere(_ > 5, 5)) // 根据开头过滤 val languages = List[String]("Java", "Python", "Perl", "Scala", "Ruby", "Kotlin", "Pascal") println(languages.indexWhere(_.startsWith("P"))) // prefixLength:已过时,推荐使用segmentLength。不满足条件的元素,第一次出现的下标 // println(list.prefixLength(_ > 5)) println(list.segmentLength(_ > 5)) } }
-
增加/更新
package com.fesco.seq object SeqDemo3 { def main(args: Array[String]): Unit = { val list = List[Int](3, 2, 1, 5, 7, 9, 8) // 尾部追加 val r1 = list :+ 4 println(r1) // 头部追加 val r2 = 3 +: list println(r2) // 扩充序列,将序列的长度扩为10 val r3 = list.padTo(10, 0) println(r3) // 更新数据 val r4 = list.updated(2, 4) println(r4) // list(2) = 4只支持可变序列 // patch(from, 子序列, 替换长度):从序列的第from下标开始,替换指定个数的元素,替换为子序列中的元素 val v = List[Int](2, 4, 6) val r5 = list.patch(3, v, 3) println(r5) } }
-
排序
package com.fesco.seq object SeqDemo4 { def main(args: Array[String]): Unit = { // 对元素进行自然排序 val list = List[Int](3, 2, 1, 5, 7, 9, 8) val r1 = list.sorted println(r1) val s1 = new Student("Amy", 15, 92) val s2 = new Student("Bob", 13, 85) val s3 = new Student("Tom", 14, 78) val s4 = new Student("Sam", 16, 91) val s5 = new Student("Tony", 17, 65) val s6 = new Student("Eden", 16, 72) val s7 = new Student("Hack", 15, 78) val students = List[Student](s1, s2, s3, s4, s5, s6, s7) // 按照学生姓名排序 // 根据元素中的某一个属性来排序 // students.sortBy(s => s.name) val namedStudents = students.sortBy(_.name) println(namedStudents) // 规则:按照分数进行降序排序,如果分数相同,则按照年龄升序 println("=" * 50) val r2 = students.sortWith((s1, s2) => if (s1.score != s2.score) s1.score > s2.score else s1.age < s2.age) println(r2) } } class Student(val name: String, val age: Int, val score: Int) { override def toString: String = s"{name:$name, age:$age, score:$score}\n" }
-
判断
package com.fesco.seq object SeqDemo5 { def main(args: Array[String]): Unit = { val list = List[Int](1, 2, 3, 4, 5) val sub = List[Int](1, 2) // startsWith println(list.startsWith(sub)) // endsWith println(list.endsWith(sub)) // 判断是否包含了指定元素 println(list.contains(3)) // 判断是否包含指定子列 println(list.containsSlice(sub)) val number = 1 :: 2 :: 3 :: 4 :: 5 :: Nil val twice = 2 :: 4 :: 6 :: 8 :: 10 :: Nil // 判断twice中的元素是否是number中对应位置上元素的2倍 // number.corresponds(twice)((x, y) => x * 2 == y) println(number.corresponds(twice)(_ * 2 == _)) } }
-
多序列操作
package com.fesco.seq object SeqDemo6 { def main(args: Array[String]): Unit = { val list1 = List[Int](2, 4, 6, 8, 10) val list2 = List[Int](1, 2, 4, 8, 16, 32) // 并集 - a ∪ b,将a和b的数据放到一起 val r1 = list1 ++: list2 println(r1) val r2 = list1 :++ list2 println(r2) val r3 = list1 concat list2 println(r3) val r4 = list1 ::: list2 println(r4) val r5 = list1 union list2 println(r5) // 交集 - a ∩ b,获取a和b都有的数据 val r6 = list1 intersect list2 println(r6) // 差集 - a有b没有的 val r7 = list1 diff list2 println(r7) // 去重 val r8 = r1.distinct println(r8) } }
-
集合(Set
)
不可变集合(Set
)
-
注意:在Scala中,无论是可变集合还是不可变集合,都是使用
Set
来定义,区别是可变集合是scala.collection.mutable.Set
,不可变集合是scala.collection.immutable.Set
-
定义格式
package com.fesco.set object SetDemo { def main(args: Array[String]): Unit = { // 不可变集合Set本身是一个特质,就意味着无法直接创建对象 // 方式一:创建空集合 val set: Set[String] = Set.empty[String] println(set) // 方式二: // 无序不可重复 val set2: Set[Int] = Set[Int](2, 4, 6, 8) println(set2) } }
-
基本操作
package com.fesco.set object SetDemo2 { def main(args: Array[String]): Unit = { val set = Set[Int](1, 3, 5, 7, 9) // 添加元素 val r1 = set + 2 println(r1) // 删除元素 val r2 = set - 3 println(r2) // 并集 val set2 = Set[Int](2, 4, 6, 8) val r3 = set ++ set2 println(r3) val r4 = set union set2 println(r4) val r5 = set concat set2 println(r5) val r10 = set | set2 println(r10) // 差集 val set3 = Set[Int](1, 2, 3, 4) val r6 = set -- set3 println(r6) val r7 = set diff set3 println(r7) val r11 = set &~ set3 println(r11) // 交集 val r8 = set intersect set3 println(r8) val r9 = set & set3 println(r9) // 遍历 set.foreach(println) } }
可变集合(Set
)
-
可变集合依然使用Set来定义
val set = mutable.Set[Int]()
-
基本操作
package com.fesco.set import scala.collection.mutable object SetDemo3 { def main(args: Array[String]): Unit = { // 创建可变集合对象 val set = mutable.Set[Int]() println(set) // 添加元素 set += 7 println(set) set add 8 println(set) // 删除元素 set -= 7 println(set) set remove 8 println(set) // 合并集合 val set1 = mutable.Set[Int](5, 5, 4, 7, 8, 9) val set2 = mutable.Set[Int](2, 4, 6, 8, 10) set1 ++= set2 println(set1) // 差集 val set3 = mutable.Set[Int](5, 4, 7, 8, 9) val set4 = mutable.Set[Int](2, 4, 6, 8, 10) set3 --= set4 println(set3) } }
映射(Map
)
不可变映射
-
注意:Scala中,可变映射和不可变映射都是通过Map来定义。默认使用的是不可变映射
-
Map本身是一个特质,无法直接创建对象,所以使用的是伴生对象
package com.fesco.map object MapDemo { def main(args: Array[String]): Unit = { // Map存储的是键值对,所以泛型需要指定2个 // 定义的时候就需要给定键值对 // 方式一 val map = Map[String, Int]("Amy" -> 85, "Bob" -> 74, "Cindy" -> 63, "David" -> 59, "Evan" -> 60) println(map) // 方式二 val map2 = Map[String, Int](("Frank", 15), ("Grace", 24), ("Henry", 36), ("Iran", 44)) println(map2) } }
-
基本操作
package com.fesco.map object MapDemo2 { def main(args: Array[String]): Unit = { val map = Map[String, Int]("Jack" -> 85, "Kathy" -> 79, "Lily" -> 64, "Mark" -> 58, "Nelson" -> 84) // 添加键值对 val r1 = map + ("Odersky" -> 75) println(r1) val r2 = map + (("Peter", 74)) println(r2) // 如果添加的键值对的键已经存在,那么对应的值来进行替换 val r3 = map + ("Lily" -> 81) println(r3) // 移除指定的键对应的键值对 val r4 = map - "Nelson" println(r4) // 获取指定键对应的值 // 为了防止空指针异常,将get函数的返回值封装成了Option类型 // 如果有实际值,那么可以从Option中获取到实际值 // 如果没有实际值,那么会从Option获取到None val r5:Option[Int] = map get "Mark" val r6:Option[Int] = map get "Rose" // println(if(!r5.isEmpty) r5.get else r5) println(if(r5.isDefined) r5.get else r5) // println(if(!r6.isEmpty) r6.get else r6) println(if(r6.isDefined) r6.get else r6) // 获取指定键对应的值,如果键存在,那么返回实际值;如果键不存在,返回指定的值 val r7 = map.getOrElse("Thomas", 0) println(r7) } }
可变映射
-
可变映射也是通过
Map
来定义 -
基本操作
package com.fesco.map import scala.collection.mutable object MapDemo3 { def main(args: Array[String]): Unit = { val map = mutable.Map[String, Int]() // 添加元素 map.put("Adair", 84) map.put("Bruce", 58) map.put("Bruce", 67) println(map) map += ("Cindy" -> 72) map += (("Danny", 72)) println(map) // 修改指定的键对应的值 map.update("Cindy", 85) map("Adair") = 96 println(map) // 获取指定的键对应的值 // get函数将结果封装成Option[Some]对象 // Option[Int] => Option[Some] val r1: Option[Int] = map.get("Bruce") println(r1) val r2: Int = map("Bruce") println(r2) val r3 = map.getOrElse("Fed", 0) println(r3) // 删除指定键对应的值 map remove "Bruce" map -= "Adair" println(map) } }
遍历映射
-
键的遍历:遍历所有的键,通过键来获取值
package com.fesco.map object MapDemo4 { def main(args: Array[String]): Unit = { val map = Map[String, Int]("Peter" -> 15, "Tony" -> 17, "Simon" -> 16, "Kohn" -> 18, "Lucy" -> 20, "Vincent" -> 21, "William" -> 20) // 键的遍历 // 方式一:keySet,将所有的键放入一个Set中返回 val keySet: Set[String] = map.keySet for (key <- keySet) println(s"key:$key, value:${map(key)}") // 方式二:keys,将所有的键放入一个Iterable中返回 println("=" * 100) val keys: Iterable[String] = map.keys for (key <- keys) println(s"key:$key, value:${map(key)}") // 方式三:keysIterator,将所有的键放入一个Iterator中返回 println("=" * 100) val keysIterator: Iterator[String] = map.keysIterator for (key <- keysIterator) println(s"key:$key, value:${map(key)}") } }
-
获取所有的值
package com.fesco.map object MapDemo5 { def main(args: Array[String]): Unit = { val map = Map[String, Int]("Peter" -> 15, "Tony" -> 17, "Simon" -> 16, "Kohn" -> 18, "Lucy" -> 20, "Vincent" -> 21, "William" -> 20) // 获取所有的值 // 方式一 val values: Iterable[Int] = map.values for (value <- values) println(value) // 方式二 println("=" * 50) val valuesIterator: Iterator[Int] = map.valuesIterator for (elem <- valuesIterator) println(elem) } }
-
遍历映射
package com.fesco.map object MapDemo6 { def main(args: Array[String]): Unit = { val map = Map[String, Int]("Peter" -> 16, "Tony" -> 17, "Simon" -> 16, "Kohn" -> 18, "Lucy" -> 20, "Vincent" -> 21, "William" -> 20) // 方式一:iterator,将键值对放入一个Iterator中返回 val it: Iterator[(String, Int)] = map.iterator for (t <- it) println(s"key:${t._1}, value:${t._2}") // 方式二:直接使用增强for循环,本质上就是一个迭代过程 println("=" * 50) for (t <- map) println(s"key:${t._1}, value:${t._2}") // 方式三:foreach函数 println("=" * 50) map.foreach(t => println(s"key:${t._1}, value:${t._2}")) } }
-
映射中的键值对实际上就是Tuple2,Tuple2又称之为对偶元组。因此,在Scala中,Map实际上就是一个存储了多个Tuple2的数组