Scala入门(七)集合

总目录

文章目录

    • 1.集合简介
      • 1.1 不可变集合继承图
      • 1.2 可变集合继承图
    • 2.数组
      • 2.1 不可变数组
      • 2.2 可变数组
      • 2.3 不可变数组与可变数组的转换
      • 2.4 多维数组
    • 3.列表List
      • 3.1 不可变List
      • 3.2 可变ListBuffer
    • 4.Set集合
      • 4.1 不可变Set
      • 4.2 可变Set
    • 5.Map集合
      • 5.1 不可变Map
      • 5.2 可变Map
    • 6.元组
    • 7.集合常用函数
      • 7.1 基本属性和常用操作
      • 7.2 衍生集合
      • 7.3 集合计算简单函数
      • 7.4 集合计算高级函数
      • 7.5 高级计算函数案例
      • 7.6 普通WordCount案例
      • 7.7 复杂WordCount案例
    • 8.队列
    • 9.并行集合

1.集合简介

1)Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable特质。

2)对于几乎所有的集合类,Scala 都同时提供了可变不可变的版本,分别位于以下两个包

不可变集合:scala.collection.immutable

可变集合: scala.collection.mutable

3)Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。

类似于 java 中的 String 对象

4)可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象

注意: 一般情况,在操作集合的时候,不可变用符号(即不可变集合使用符号进行操作),可变用方法(可变集合使用方法进行操作)

1.1 不可变集合继承图

Scala入门(七)集合_第1张图片
1)Set、Map 是 Java 中也有的集合

2)Seq 是 Java 没有的, List 归属到 Seq 了,因此这里的 List 就和 Java 不是同一个概念了

3)前面的 for 循环有一个 1 to 3,就是 IndexedSeq 下的 Range

4)String 也是属于 IndexedSeq

5)经典的数据结构比如 Queue 和 Stack 被归属到 LinearSeq(线性序列)

6)注意 Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map 可以支持排序

7)IndexedSeq 和 LinearSeq 的区别:

(1)IndexedSeq 是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集合,通过索引即可定位

(2)LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找

1.2 可变集合继承图

Scala入门(七)集合_第2张图片

2.数组

2.1 不可变数组

1)第一种方式定义数组

定义:val arr = new Array[Int](10)

(1)new 是关键字

(2)[Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定 Any

(3)(10),表示数组的大小,确定后就不可以变化

2)案例

object Test_Array {
    def main(args: Array[String]): Unit = {
        // 创建数组
        val arr01: Array[Int] = new Array[Int](5)
        println(arr01.length) // 5
        // 访问数组中某个元素
        // 在访问元素时,arr(0)其实就是arr01.apply(0),是调用Array类的apply方法;但arr01.apply(0) = 1是不行的
        println(arr01(1)) // 0
        //(2)数组赋值
        //(2.1)修改某个元素的值
        arr01(3) = 10
        //(2.2)采用方法的形式给数组赋值
        arr01.update(0,1)
        //(3)遍历数组
        //(3.1)查看数组
        println(arr01.mkString(","))
        //(3.2)普通遍历
        // for(i <- 0 until arr01.length) println(arr01(i))
        // indices在源码中的解释是def indices: Range = 0 until length
        // for(i <- arr01.indices) println(arr01(i))
        for (i <- arr01) println(i)
        // 迭代器
        // val iter = arr01.iterator
        // while (iter.hasNext) println(iter.next())
        //(3.3)简化遍历
        // arr01.foreach((x)=>{println(x)})
        // arr01.foreach(println(_))
        arr01.foreach(println)
        //(4)增加元素(由于创建的是不可变数组,增加元素,其实是产生新的数组,可以通过输出前后地址验证)
        println(arr01.mkString(","))
        // :+ 在后方追加
        // arr01 :+ 5也可以(注:在后面添加Array应在符号前)
        val newArr: Array[Int] = arr01.:+(5)
        println(newArr.mkString(","))
        // +: 在最前方添加
        // 3 +: newArr也可以(注:在前面添加Array应在符号后)
        val newArr1: Array[Int] = newArr.+:(3)
        println(newArr1.mkString(","))
    }
}

3)第二种方式定义数组

val arr1 = Array(1, 2)

(1)在定义数组时,直接赋初始值

(2)使用 apply 方法创建数组对象

4)案例

object Test_Array {
    def main(args: Array[String]): Unit = {
        // 实际是调用了apply方法。Array.apply(1, 3, 5)
        val arr02 = Array(1, 3, 5)
        println(arr02.length)
        for (i <- arr02) {
            println(i)
        }
    }
}

2.2 可变数组

1)定义变长数组

val arr01 = ArrayBuffer[Any](1, 3, 5)

(1)[Any]存放任意数据类型

(2)(1, 3, 5)初始化好的三个元素

(3)ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer

注意:(1)ArrayBuffer 是有序的集合

(2)增加元素使用的是 append 方法(),支持可变参数

object Test_ArrayBuffer {
    def main(args: Array[String]): Unit = {
        // 创建可变数组
        // val arr1 = new ArrayBuffer[Int]()
        // 利用apply方法创建ArrayBuffer对象
        val arr1 = ArrayBuffer(1, 3, 5)

        // 访问元素
        println(arr1(0))

        // 修改元素
        // arr1(0) = 3
        // println(arr1.mkString(","))

        // 遍历与不可变数组类似,不再赘叙

        // 添加元素
        // 不可变数组一般使用符号(虽然可变数组也可用,但不推荐,因为会创建一个新的数组)
        val newArr = arr1 :+ 13
        println(newArr.mkString(","))
        println(arr1 == newArr) // false
        // 可变数组常见添加元素操作,但不推荐进行类似于arr1 += 13这种操作后赋值(这个与不可变数组相异)
        // 因为赋值的是引用,故而一个改变,另一个也会改变
        // val newArr1 = arr1 += 13
        // println(newArr1.mkString(","))
        // println(arr1 == newArr1)  // true,引用相等
        // 后面追加
        // arr1 += 13
        // println(arr1.mkString(","))
        // 前面添加
        // 13 +=: arr1
        // println(arr1.mkString(","))
        // 可变集合更推荐使用方法而非符号(虽然符号也是方法,但此处指的是那种明确的英文名称方法)
        // 末尾添加,可以添加多个
        arr1.append(13)
        println(arr1.mkString(","))
        // 前面添加,可以添加多个
        arr1.prepend(13)
        println(arr1.mkString(","))
        // 指定位置添加,可以添加多个(第一个参数是索引,其余是要添加的元素)
        arr1.insert(1, 13)
        println(arr1.mkString(","))
        // insertAll方法可以直接在指定位置将一个数组所有元素加入
        // 相应的还有appendAll和prependAll,就不再赘叙
        arr1.insertAll(1, Array(1, 3, 5))
        println(arr1.mkString(","))

        // 删除元素
        // remove(n: Int),n是索引,即删除指定索引位置元素
        arr1.remove(3)
        println(arr1.mkString(","))
        // remove(n: Int, count: Int),n是索引,count是数目,即删除指定索引位置元素count个元素
        arr1.remove(3, 2)
        println(arr1.mkString(","))
        // 按照元素本身的值来进行删除(需要使用符号),只会删除第一个对应的元素
        arr1 -= 13
        println(arr1.mkString(","))
    }
}

2.3 不可变数组与可变数组的转换

1)说明

arr1.toBuffer //不可变数组转可变数组

arr2.toArray //可变数组转不可变数组

(1)arr2.toArray 返回结果才是一个不可变数组,arr2 本身没有变化

(2)arr1.toBuffer 返回结果才是一个可变数组,arr1 本身没有变化

2)案例

// 不可变数组与可变数组的转换
val arr: ArrayBuffer[Int] = ArrayBuffer(1, 3, 5)
// 可变转变为不可变
val newArr2: Array[Int] = arr.toArray
println(newArr2.mkString(","))
println(arr)
// 不可变转变为可变
val buffer = newArr2.toBuffer
println(buffer)
println(newArr2)

2.4 多维数组

1)多维数组定义

val arr = Array.ofDim[Double](3,4)

说明:二维数组中有三个一维数组,每个一维数组中有四个元素

2)案例

object Test_MulArray {
    def main(args: Array[String]): Unit = {
        // 创建二维数组
        // ofDim方法可以用于创建多维数组(最高5维),参数的数目即是维度
        // 如下示例即为二维数组,二行三列
        val array: Array[Array[Int]] = Array.ofDim[Int](2, 3)

        // 访问元素
        println(array(0)(1))

        // 赋值
        array(0)(1) = 1
        println(array(0)(1))

        // 遍历(不可直接使用mkString,会输出引用)
        // for(i <- 0 until array.length; j <- 0 until array(i).length) println(array(i)(j))
        // for(i <- array.indices; j <- array(i).indices) println(array(i)(j))
        // array.foreach(line => line.foreach(println))
        // array.foreach(_.foreach(println))
        for(i <- array.indices) println(array(i).mkString(","))
    }
}

3.列表List

3.1 不可变List

1)说明

(1)List 默认为不可变集合

(2)创建一个 List(数据有顺序,可重复)

(3)遍历 List

(4)List 增加数据

(5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化

(6)取指定数据

(7)空集合 Nil

2)案例

object Test_List {
    def main(args: Array[String]): Unit = {
        // 创建一个List
        // 由于List本身是一个抽象类
        // 且被sealed(密封,用此修饰后,当前类的子类不可定义在类文件之外)修饰,故不可直接用new关键字创建
        // 在此处是调用List类伴生对象的apply方法创建的
        val list1 = List(1, 3, 5)
        println(list1)

        // 访问List元素
        // list1(1) = 10这类赋值操作不行
        println(list1(1))

        // 遍历List元素
        // list1.foreach(println)

        // 添加元素
        // 列表头部添加
        // 10 +: list1也可以
        val list2 = list1.+:(10)
        // 列表尾部添加
        // list2 :+ 10也可以
        val list3 = list1.:+(10)
        println(list2)
        println(list3)

        println("-------------------------")

        // 可以用于在列表头部添加元素,但一般不这么使用
        val list4 = list1.::(10)
        println(list4)
        // 一般用于配合Nil(空列表)创建新列表
        val list5 = Nil.::(10)
        println(list5)
        val list6 = 10 :: Nil
        println(list6)
        val list7 = 10 :: 13 :: 15 :: Nil
        println(list7)

        // 合并列表
        // 在这里是直接把整个列表加入另一个列表的头部,而非将数据合并
        val list8 = list6 :: list7
        println(list8)
        // 将后一个列表的元素合并前一个列表的尾部
        // 扁平化:将整体拆分为一个一个的个体
        // list6 ++ list7也可以
        val list9 = list6 ::: list7
        println(list9)
    }
}

3.2 可变ListBuffer

1)说明

(1)创建一个可变集合 ListBuffer

(2)向集合中添加数据

(3)打印集合数据

2)案例

object Test_ListBuffer {
    def main(args: Array[String]): Unit = {
        // 创建可变列表
        // 利用new关键字创建
        // val list1: ListBuffer[Int] = new ListBuffer[Int]()
        // 利用伴生对象的apply方法创建
        val list1: ListBuffer[Int] = ListBuffer(1, 3, 5)
        println(list1)
        println("------------------------")

        // 添加元素
        // 在头部添加
        list1.prepend(10, 13)
        println(list1)
        println("------------------------")
        // 在尾部添加
        list1.append(10, 13)
        println(list1)
        println("------------------------")
        // 指定位置添加
        list1.insert(1, 1, 3)
        println(list1)
        println("------------------------")
        // 用符号添加
        // 尾部添加
        // list1 += 10 += 13
        // println(list1)
        // println("------------------------")
        // 头部添加
        // 10 +=: 13 +=: list1
        // println(list1)
        // println("------------------------")
        // 同时使用
        // 10 +=: 13 +=: list1 += 10 += 13
        // println(list1)
        // println("------------------------")

        // 合并列表
        // 此种方法list1与list2的值不会发生改变
        val list2: ListBuffer[Int] = ListBuffer(10, 13)
        val list3 = list1 ++ list2
        println(list3)
        println("------------------------")
        // 此种方法list1会发生改变,list2不会改变,是在list1尾部添加
        list1 ++= list2
        println(list1)
        println("------------------------")
        // 此种方法是list2会发生改变,list1不会改变,是在list2头部添加
        list1 ++=: list2
        println(list2)
        println("------------------------")

        // 修改元素
        // 实则是调用了update方法
        // list2.update(1, 30)
        list2(1) = 30
        println(list2)
        println("------------------------")

        // 删除元素
        // 删除指定位置的元素
        list2.remove(1)
        println(list2)
        println("------------------------")
        // 删除指定的元素
        // 只会删除第一次出现的
        list2 -= 10
        println(list2)
    }
}

4.Set集合

默认情况下,Scala 使用的是不可变集合,如果想使用可变集合,需要引用scala.collection.mutable.Set 包。

4.1 不可变Set

1)说明

(1)Set 默认是不可变集合,数据无序

(2)数据不可重复

(3)遍历集合

2)案例

object Test_ImmutableSet {
    def main(args: Array[String]): Unit = {
        // 创建set
        // 同样,由于Set是一个特质,不可使用new关键字创建对象
        // 在此处使用其伴生对象的apply方法创建
        // 如果有重复的元素会自动去重
        val set1: Set[Int] = Set(1, 3, 5)
        println(set1)
        println("------------------------------")

        // 添加元素
        // 由于Set无序,所以添加的位置无意义
        // set1.+(20)
        val set2 = set1 + 20
        println(s"set1 = $set1")
        println(s"set2 = $set2")
        println("------------------------------")

        // 合并Set
        val set3 = Set(10, 13)
        // +不能完成此操作,只能用来添加元素
        // 在合并时,相同的元素会进行去重
        val set4 = set2 ++ set3
        println(set4)
        println("------------------------------")

        // 删除元素
        val set5 = set3 - 13
        println(s"set3 = $set3")
        println(s"set5 = $set5")
        println("------------------------------")
    }
}

4.2 可变Set

1)说明

(1)创建可变集合 mutable.Set

(2)打印集合

(3)集合添加元素

(4)向集合中添加元素,返回一个新的 Set

(5)删除数据

2)案例

object Test_MutableSet {
    def main(args: Array[String]): Unit = {
        // 创建Set
        // 如果直接使用Set创建,默认会创建不可变的集合
        val set1 = mutable.Set(1, 3, 5)
        println(set1)
        println("-------------------------")

        // 添加元素
        // 直接使用+,集合内容不改变
        // 若不进行赋值,原值不改变
        // val set2 = set1 + 13(set2值即为已添加元素的数组)
        // println(set1)
        // println(set2)
        set1 += 13
        println(set1)
        println("-------------------------")
        // add方法返回值为Boolean,具体实现见源码(实际上还是调用了+=)
        // 若是集合中已经存在,则返回false,反之返回true
        set1.add(10)
        println(set1)
        println("-------------------------")

        // 删除元素
        set1 -= 10
        println(set1)
        println("-------------------------")
        // remove方法返回值为Boolean,具体实现见源码(实际上还是调用了-=)
        // 若是集合中不存在,则返回false,反之返回true
        set1.remove(13)
        println(set1)
        println("-------------------------")

        // 合并集合
        // 合并时会进行去重
        val set3 = mutable.Set(10, 13)
        println(set1)
        println(set3)
        println("-------------------------")
        val set4 = set1 ++ set3
        println(set1)
        println(set3)
        println(set4)

        println("-------------------------")
        set1 ++= set3
        println(set1)
        println(set3)
    }
}

5.Map集合

Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value)映射。

5.1 不可变Map

1)说明

(1)创建不可变集合 Map

(2)循环打印

(3)访问数据

(4)如果 key 不存在,返回 0

2)案例

object Test_ImmutableMap {
    def main(args: Array[String]): Unit = {
        // 创建Map
        // 默认为不可变类型,且由于Map是特征,不能直接new
        // 且不可变Map不能直接添加元素
        val map1: Map[String, Int] = Map("1" -> 1, "2" -> 2, "3" -> 3)
        println(map1)
        // 由于有三个元素,故而为Map3
        println(map1.getClass)  // class scala.collection.immutable.Map$Map3
        println("-----------------------------")

        // 遍历元素
        // 非简写形式:map1.foreach( (kv: (String, Int)) => println(kv) )
        map1.foreach(println)
        println("-----------------------------")

        // 访问某一个key的value
        // get返回值为Option类型,可防止空指针异常,将其包装成Option来处理
        println(map1.get("1"))
        // Some取值可用get方法,返回值即为value的值
        println(map1.get("1").get)
        // 若获取不存在的键,则结果为None
        // 注:在此种情况下不能使用Some的get方法,会抛出异常
        println(map1.get("10"))
        // 若使用getOrElse方法,存在则返回相应值,不存在则返回指定默认值
        println(map1.getOrElse("10", 0))
        // 类似于get.get,若不存在会抛出异常
        println(map1("1"))
        println("-----------------------------")

        // 取map中所有的key或者所有的value
        for(key <- map1.keys) {
            println(s"$key -> ${map1.get(key)}")
        }
    }
}

5.2 可变Map

1)说明

(1)创建可变集合

(2)打印集合

(3)向集合增加数据

(4)删除数据

(5)修改数据

2)案例

object Test_MutableMap {
    def main(args: Array[String]): Unit = {
        // 创建Map
        val map1: mutable.Map[String, Int] = mutable.Map("1" -> 1, "2" -> 2, "3" -> 3)
        println(map1)
        // HashMap是无序的
        println(map1.getClass)
        println("----------------------------")

        // 添加元素
        map1.put("4", 4)
        map1.put("5", 5)
        println(map1)
        println("----------------------------")

        map1 += (("6", 6))
        map1 += (("7", 7))
        println(map1)
        println("----------------------------")

        // 删除元素
        // 只需要指定key就行了
        println(map1.get("7"))
        map1.remove("7")
        println(map1.getOrElse("7", 0))

        map1 -= "5"
        println(map1)
        println("----------------------------")

        // 修改元素
        map1.update("3", 333)
        println(map1)

        map1 += (("3", 777))
        println(map1)
        println("----------------------------")

        // 合并Map
        val map2: Map[String, Int] = Map("10" -> 10, "13" -> 13)
        // 注:不仅仅是添加,如果有相同的key,会以map2的value覆盖
        // 可变Map与上述类似
        map1 ++= map2
        println(map1)
        // 不可变Map不可直接添加合并,但可以通过赋给新的对象来实现
        val map3: Map[String, Int] = map2 ++ map1
        println(map3)
    }
}

6.元组

1)说明

元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为

一个整体,称为元组。

注意:元组中最大只能有 22 个元素。

2)案例

(1)声明元组的方式:(元素 1,元素 2,元素 3)

(2)访问元组

(3)Map 中的键值对其实就是元组,只不过元组的元素个数为 2,称之为对偶

object Test_Tuple {
    def main(args: Array[String]): Unit = {
        // 创建元组
        val tuple: (Int, String, Boolean) = (1, "2", true)
        println(tuple)
        println("-------------------------")

        // 访问数据
        // _i属性代表着元组中第i个元素
        println(tuple._1)
        // productElement(index),index是下标
        println(tuple.productElement(0))
        println("-------------------------")

        // 遍历元组数据
        for(elem <- tuple.productIterator) {
            println(elem)
        }

        // 嵌套元组
        val mulTuple = (1, 10, (1, 3, 5))
        println(mulTuple._3._1)
    }
}

7.集合常用函数

7.1 基本属性和常用操作

1)说明

(1)获取集合长度

(2)获取集合大小

(3)循环遍历

(4)迭代器

(5)生成字符串

(6)是否包含

2)案例

object Test_CommonOp {
    def main(args: Array[String]): Unit = {
        val list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

        //(1)获取集合长度
        println(list1.length)
        println("---------------------------")
        //(2)获取集合大小,等同于 length
        println(list1.size)
        println("---------------------------")
        //(3)循环遍历
        list1.foreach(println)
        println("---------------------------")
        //(4)迭代器
        for (elem <- list1.iterator) {
            println(elem)
        }
        println("---------------------------")
        //(5)生成字符串
        println(list1.mkString(","))
        println("---------------------------")
        //(6)是否包含
        println(list1.contains(3))
        println("---------------------------")
    }
}

7.2 衍生集合

1)说明

(1)获取集合的头

(2)获取集合的尾(不是头的就是尾)

(3)集合最后一个数据

(4)集合初始数据(不包含最后一个)

(5)反转

(6)取前(后)n 个元素

(7)去掉前(后)n 个元素

(8)并集

(9)交集

(10)差集

(11)拉链

(12)滑窗

2)案例

object Test_DerivedCollection {
    def main(args: Array[String]): Unit = {
        val list1 = List(1, 3, 5)
        val list2 = List(10, 13)

        //(1)获取集合的头
        println(list1.head)
        println("----------------------------")
        //(2)获取集合的尾(并非最后一个元素)
        println(list1.tail)
        println("----------------------------")
        //(3)集合最后一个数据
        println(list1.last)
        println("----------------------------")
        //(4)集合初始元素(即不包含最后一个元素的其他元素集合)
        println(list1.init)
        println("----------------------------")
        //(5)反转
        println(list1.reverse)
        println("----------------------------")
        //(6)取前(后)n 个元素
        println(list1.take(2))
        println(list1.takeRight(2))
        println("----------------------------")
        //(7)去掉前(后)n 个元素
        println(list1.drop(2))
        println(list1.dropRight(2))
        println("----------------------------")
        //(8)并集
        // 如果是用set去做并集,会自动去重
        println(list1.union(list2))
        println(list1 ::: list2)
        println("----------------------------")
        //(9)交集
        println(list1.intersect(list2))
        println("----------------------------")
        //(10)差集
        println(list1.diff(list2))
        println(list2.diff(list1))
        println("----------------------------")
        // (11)拉链(将两个集合对应位置元素配对,形成二元组,如果某个集合有多余的部分则会直接去掉)
        println(list1.zip(list2))
        println(list2.zip(list1))
        println("----------------------------")
        // (12)滑窗
        // 获取大小为2的滑动窗口
        // list1.sliding(2)得到的是一个迭代器(iterator)
        // 结果解释:(1, 3, 5) 获取一个大小为二的滑动窗口,初始即为(1, 3),进行滑动,即为(3, 5)
        // 若初始为(1, 3, 5, 10, 13),窗口大小为3,则结果应为(1, 3, 5),(3, 5, 10),(5, 10, 13)
        // 可以设置第二个参数步长,即为窗口一次滑动的距离
        for(elem <- list1.sliding(2)) {
            println(elem)
        }
    }
}

7.3 集合计算简单函数

1)说明

(1)求和

(2)求乘积

(3)最大值

(4)最小值

(5)排序

2)案例

object Test_SimpleFunction {
    def main(args: Array[String]): Unit = {
        val list: List[Int] = List(1, 3, 5, 10, 13)
        val list2 = List(("1", 1), ("2", 2), ("3", 3))

        //(1)求和
        println(list.sum)
        println("----------------------------")
        //(2)求乘积
        println(list.product)
        println("----------------------------")
        //(3)最大值
        // 如果集合内部存在元组类型,则只取第一个进行比较
        println(list.max)
        // 对具体情况进行处理再来寻找最大值
        // println(list2.maxBy((tuple: (String, Int)) => tuple._2))
        // 简写形式
        println(list2.maxBy(_._2))
        println("----------------------------")
        //(4)最小值
        println(list.min)
        println(list2.minBy(_._2))
        println("----------------------------")
        //(5)排序
        // 5.1 sorted
        println(list.sorted)
        // 从大到小逆序排列
        println(list.sorted.reverse)
        // 传入隐式参数
        println(list.sorted(Ordering[Int].reverse))
        println("----------------------------")
        // 5.2 sortBy
        println(list2.sorted)
        println(list2.sortBy(_._2))
        println(list2.sortBy(_._2)(Ordering[Int].reverse))
        println("----------------------------")
        // 5.3 sortWith
        // 从小到大排序
        // println(list.sortWith((x, y) => x < y))
        // 简写形式
        println(list.sortWith(_ < _))
        // 从大到小排序
        // println(list.sortWith((x, y) => x > y))
        println(list.sortWith(_>_))
        println("----------------------------")
    }
}

(1)sorted

对一个集合进行自然排序,通过传递隐式的 Ordering

(2)sortBy

对一个属性或多个属性进行排序,通过一定的形式。

(3)sortWith

基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑。

7.4 集合计算高级函数

1)说明

(1)过滤

遍历一个集合并从中获取满足指定条件的元素组成一个新的集合

(2)转化/映射(map)

将集合中的每一个元素映射到某一个函数

(3)扁平化

(4)扁平化+映射

注:flatMap 相当于先进行 map 操作,在进行 flatten 操作

集合中的每个元素的子元素映射到某个函数并返回新集合

(5)分组(group)

按照指定的规则对集合的元素进行分组

(6)简化(归约)

(7)折叠

2)案例

object Test_HighLevelFunction_Map {
    def main(args: Array[String]): Unit = {
        val list = List(1, 3, 5, 10, 13)

        // 过滤
        // 选取偶数
        // val evenList = list.filter(elem => elem % 2 == 0)
        val evenList = list.filter(_ % 2 == 0)
        println(evenList)
        // 选取奇数
        println(list.filter(_ % 2 == 1))
        println("----------------------------")

        // map映射
        // 将集合中每个数乘3
        println(list.map(_ * 3))
        println("----------------------------")

        // 扁平化
        val nestedList: List[List[Int]] = List(List(1, 3, 5), List(10, 13))

        val flatList = nestedList(0) ::: nestedList(1)
        println(flatList)

        val flatList2 = nestedList.flatten
        println(flatList2)
        println("----------------------------")

        // 扁平映射
        // 将一组字符串分词并保存为单词列表
        val strings: List[String] = List("hello scala", "hello spark", "hello java")
        val splitList: List[Array[String]] = strings.map(_.split(" "))
        val flattenList = splitList.flatten // 打散扁平化
        println(flattenList)

        val flatmapList = strings.flatMap(_.split(" "))
        println(flatmapList)
        println("----------------------------")

        // 分组groupBy
        // 分成奇偶两组
        val groupMap1: Map[String, List[Int]] = list.groupBy(data => {
            if(data % 2 == 0) "偶数" else "奇数"
        })
        println(groupMap1)
        // 简写形式
        val groupMap2: Map[Int, List[Int]] = list.groupBy(_ % 2)
        println(groupMap2)

        // 给定一组词汇,按单词首字母分组
        val wordList = List("china", "america", "test")
        println(wordList.groupBy(_.charAt(0)))
    }
}

3)集合转换操作(Reduce)

Reduce 简化(归约) :通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最终获取结果。

案例

object Test_HighLevelFunction_Reduce {
    def main(args: Array[String]): Unit = {
        val list = List(1, 3, 5)

        // reduce
        // reduce底层是调用了reduceLeft
        println(list.reduce(_ + _))
        // 从左往右
        println(list.reduceLeft(_ + _))
        // 从右往左
        println(list.reduceRight(_ + _))
        println("-----------------------------------")

        val list2 = List(10, 13)
        println(list2.reduce(_ - _))
        println(list2.reduceLeft(_ - _))
        // 看reduceRight源码,可发现reduceRight实际还是从左往右
        println(list2.reduceRight(_ - _)) // ( 10 - (13))
    }
}

4)Fold方法

Fold 折叠:化简的一种特殊情况。

案例

object Test_Fold {
    def main(args: Array[String]): Unit = {
        val list = List(1, 3, 5)
        val list2 = List(10, 13, 10)

        // fold
        println(list.fold(10)(_ + _)) // 10 + 1 + 3 + 5
        println(list.foldLeft(10)(_ - _)) // 10 - 1 - 3 - 5
        // 仍是由左往右减,但首先应该用最后一个值减去初始值,具体实现可见源码
        // (10, 13, 10),10 - (13 - (10 - 11)),-4
        println(list2.foldRight(11)(_ - _)) // 10 - (13 - 11)
    }
}

7.5 高级计算函数案例

合并Map

Map的合并会存在一种问题,例如map1 ++= map2,不存在的key会加入,但已存在的key会进行覆盖,在某些场

景下这样做反而不适用。

object Test_MergeMap {
    def main(args: Array[String]): Unit = {
        val map1 = mutable.Map("1" -> 1, "2" -> 2, "3" -> 3, "10" -> 1010, "13" -> 333)
        val map2 = Map("10" -> 10, "13" -> 13)

        // 在此处不能使用fold,只能使用foldLeft(map1与map2类型不同)
        val map3 = map2.foldLeft(map1) {
            (mergedMap, kv) => {
                val key = kv._1
                val value = kv._2
                mergedMap(key) = mergedMap.getOrElse(key, 0) + value
                mergedMap
            }
        }

        println(map3)
    }
}

7.6 普通WordCount案例

1)需求

单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果

2)需求分析
Scala入门(七)集合_第3张图片
3)案例

object Test_CommonWordCount {
    def main(args: Array[String]): Unit = {
        val stringList: List[String] = List(
            "hello",
            "hello scala",
            "hello spark",
            "hello flink",
            "hello spark from scala"
        )

        // 对字符串进行切分,得到一个打散所有单词的列表
        // val wordList1: List[Array[String]] = stringList.map(_.split(" "))
        // val wordList2: List[String] = wordList1.flatten
        // println(wordList2)
        val wordList = stringList.flatMap(_.split(" "))
        println(wordList)
        println("-------------------------------")

        // 相同的单词进行分组
        val groupMap: Map[String, List[String]] = wordList.groupBy(word => word)
        println(groupMap)
        println("-------------------------------")

        // 对分组之后的List去长度来获取各个单词的个数
        val countMap: Map[String, Int] = groupMap.map(kv => (kv._1, kv._2.length))

        // 将map转为list,并排序取前三
        val sortList: List[(String, Int)] = countMap.toList.sortWith(_._2 > _._2).take(3)
        println(sortList)
    }
}

7.7 复杂WordCount案例

`object Test_ComplexWordCount {
    def main(args: Array[String]): Unit = {
        val tupleList: List[(String, Int)] = List(
            ("hello", 1),
            ("hello scala", 3),
            ("hello spark", 5),
            ("hello flink", 10),
            ("hello spark from scala", 13)
        )

        // 思路一:直接展开为普通版本
        val newStringList = tupleList.map(
            kv => {
                // 句子数目乘以数量,即包含了所有的词汇
                // 加一个空格是为了防止单词连在一起
                (kv._1.trim + " ") * kv._2
            }
        )
        println(newStringList)
        println("------------------------")

        // 之后操作与之前WordCount完全一致
        val wordCountList: List[(String, Int)] = newStringList
        .flatMap(_.split(" "))
        .groupBy(word => word)
        .map(kv => (kv._1, kv._2.length))
        .toList.sortWith(_._2 > _._2)
        .take(3)
        println(wordCountList)
        println("------------------------")

        // 思路二:直接基于预统计的结果进行转换
        // 将字符串打散成单词,并结合相应的个数包装成二元组
        val preCountList: List[(String, Int)] = tupleList.flatMap(
            tuple => {
                val strings: Array[String] = tuple._1.split(" ")
                strings.map(word => (word, tuple._2))
            }
        )
        println(preCountList)
        println("------------------------")

        // 对二元组按照单词进行分组
        val preCountMap: Map[String, List[(String, Int)]] = preCountList.groupBy(_._1)
        println(preCountMap)
        println("------------------------")

        // 叠加每个单词预统计的个数值
        val countMap: Map[String, Int] = preCountMap.mapValues(
            tupleList => tupleList.map(_._2).sum
        )
        println(countMap)
        println("------------------------")

        // 转换成List,排序取前三
        val countList: List[(String, Int)] = countMap.toList.sortWith(_._2 > _._2).take(3)
        println(countList)
    }
}

8.队列

1)说明

Scala 也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为 enqueue 和

dequeue。

2)案例

object Test_Queue {
    def main(args: Array[String]): Unit = {
        // 创建一个可变队列
        val queue: mutable.Queue[String] = new mutable.Queue[String]()

        // 入队方法没有返回值(即返回值为空)
        queue.enqueue("a", "b", "c")
        println(queue)

        // 出队方法有返回值,返回值为出队的元素
        println(queue.dequeue())
        println(queue)

        // 不可变队列
        // 不可变队列本身不可改变
        val queue2 = Queue("a", "b", "c")
        val queue3 = queue2.enqueue("e")
        println(queue3)
    }
}

9.并行集合

1)说明

Scala 为了充分使用多核 CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。

2)案例

object Test_Parallel {
    def main(args: Array[String]): Unit = {
        val result: immutable.IndexedSeq[Long] = (1 to 100).map(
            x => Thread.currentThread.getId
        )
        println(result)

        // 有很多不同线程在执行,故结果与前者不同
        val result2: ParSeq[Long] = (1 to 100).par.map(
            x => Thread.currentThread.getId
        )
        println(result2)
    }
}

你可能感兴趣的:(Scala,scala,java,开发语言)