Scala (三)集合

一、集合简介

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

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

不可变集合:scala.collection.immutable

可变集合: scala.collection.mutable

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

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

建议:在操作集合的时候,不可变用符号,可变用方法

1.1 不可变集合继承图

img

1)Set、Map是Java中也有的集合
2)Seq是Java没有的,我们发现List归属到Seq了,因此这里的List就和Java不是同一个概念了
3)我们前面的for循环有一个 1 to 3,就是IndexedSeq下的Vector
4)String也是属于IndexeSeq
5)我们发现经典的数据结构比如Queue和Stack被归属到LinerSeq
6)大家注意Scala中的Map体系有一个SortedMap,说明Scala的Map可以支持排序
7)IndexSeq和LinearSeq的区别:

  • IndexSeq是通过索引来查找和定位,因此速度快,比如String就是一个索引集合,通过索引即可定位
  • LineaSeq是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找

1.2 可变集合继承图

img

二、数组

2.1 不可变数组

1)第一种方式定义数组(定长数组)

定义:

val arr1 = new Array[Int](10)

(1)new是关键字
(2)[Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定Any
(3)(10),表示数组的大小,确定后就不可以变化

2)案例实操

import scala.collection.mutable.ArrayBuffer
object TestArray{
  def main(args: Array[String]): Unit = {
    //(1)数组定义
    val arr01 = new Array[Int](4)
    println(arr01.length) // 4
    //(2)数组赋值
    //(2.1)修改某个元素的值
    arr01(3) = 10
    //(2.2)采用方法的形式给数组赋值
    arr01.update(0,1)
    //(3)遍历数组
    //(3.1)查看数组
    println(arr01.mkString(","))
    //(3.2)普通遍历
    for (i <- arr01) {
      println(i)
    }

    //(3.3)简化遍历
    def printx(elem:Int): Unit = {
      println(elem)
    }
    arr01.foreach(printx)
    // arr01.foreach((x)=>{println(x)})
    // arr01.foreach(println(_))
    arr01.foreach(println)
    //(4)增加元素(由于创建的是不可变数组,增加元素,其实是产生新的数组)
    println(arr01)
    val ints: Array[Int] = arr01 :+ 5
    println(ints)
  }
}

输出:

4
1,0,0,10
1
0
0
10
1
0
0
10
1
0
0
10
[I@6bdf28bb
[I@30c7da1e

3)第二种方式定义数组

val arr1 = Array(1, 2)

(1)在定义数组时,直接赋值
(2)使用apply方法创建数组对象

4)案例实操

object TestArray{
    def main(args: Array[String]): Unit = {
        var arr02 = Array(1, 3, "bobo")
        for (i <- arr02) {
            println(i)
        }
    }
}

输出:

1
3
bobo

2.2 可变数组

1)定义变长数组

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

(1)[Any]存放任意数据类型
(2)(3, 2, 5)初始化好的三个元素
(3)ArrayBuffer需要引入scala.collection.mutable.ArrayBuffer

2)案例实操
(1)ArrayBuffer是有序的集合
(2)增加元素使用的是append方法(),支持可变参数

import scala.collection.mutable.ArrayBuffer

object TestArrayBuffer {
  def main(args: Array[String]): Unit = {
    //(1)创建并赋值可变数组
    val arr01 = ArrayBuffer[Any](1, 2, 3)
    //(2)遍历数组
    for (i <- arr01) {
      println(i)
    }
    println(arr01.length) // 3
    println("arr01.hash=" + arr01.hashCode())
    //(3)增加元素
    //(3.1)追加数据
    arr01.+=(4)
    //(3.2)向数组最后追加数据
    arr01.append(5,6)
    //(3.3)向指定的位置插入数据
    arr01.insert(0,7,8)
    println("arr01.hash=" + arr01.hashCode())
    //(4)修改元素
    arr01(1) = 9 //修改第2个元素的值
    println("--------------------------")
    for (i <- arr01) {
      println(i)
    }
    println(arr01.length) // 5
  }
}

输出:

1
2
3
3
arr01.hash=387518613

arr01.hash=-253706129

--------------------------

7
9
1
2
3
4
5
6
8

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

1)说明

arr1.toBuffer  //不可长数组转可变数组
arr2.toArray  //可变数组转不可变数组

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

2)案例实操

object TestArrayBuffer {
  def main(args: Array[String]): Unit = {
    //(1)创建一个空的可变数组
    val arr2 = ArrayBuffer[Int]()
    //(2)追加值
    arr2.append(1, 2, 3)
    println(arr2) // 1,2,3

    //(3)ArrayBuffer ==> Array
    //(3.1)arr2.toArray 返回的结果是一个新的定长数组集合
    //(3.2)arr2它没有变化
    val newArr = arr2.toArray
    println(newArr)
    //(4)Array ===> ArrayBuffer
    //(4.1)newArr.toBuffer 返回一个变长数组 newArr2
    //(4.2)newArr 没有任何变化,依然是定长数组
    val newArr2 = newArr.toBuffer
    newArr2.append(123)
    println(newArr2)
  }
}

输出:

ArrayBuffer(1, 2, 3)
[I@5b464ce8
ArrayBuffer(1, 2, 3, 123)

1.4 多维数组

1)多维数组定义

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

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

2)案例实操

object DimArray {
  def main(args: Array[String]): Unit = {
    //(1)创建了一个二维数组, 有三个元素,每个元素是,含有4个元素一维数组()
    val arr = Array.ofDim[Int](3, 4)
    arr(1)(2) = 88
    //(2)遍历二维数组
    for (i <- arr) { //i 就是一维数组
      for (j <- i) {
        print(j + " ")
      }
      println()
    }
  }
}

输出:

0 0 0 0
0 0 88 0
0 0 0 0

三、Seq集合(List)

3.1 不可变List

1)说明

(1)List默认为不可变集合
(2)创建一个List(数据有顺序,可重复)
(3)遍历List
(4)List增加数据
(5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化
(6)取指定数据
(7)空集合Nil

2)案例实操

object TestList {
  def main(args: Array[String]): Unit = {
    //(1)List默认为不可变集合
    //(2)创建一个List(数据有顺序,可重复)
    val list: List[Int] = List(1,2,3,4,3)

    //(7)空集合Nil
    val list5 = 1::2::3::4::Nil

    //(4)List增加数据
    //(4.1)::的运算规则从右向左
    //val list1 = 5::list
    val list1 = 7::6::5::list
    //(4.2)添加到第一个元素位置
    val list2 = list.+:(5)

    //(5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化
    val list3 = List(8,9)
    //val list4 = list3::list1
    val list4 = list3:::list1

    //(6)取指定数据
    println(list(0))// 1

    //(3)遍历List
    //list.foreach(println)  // 1 2 3 4 3
    //list1.foreach(println) // 7 6 5 1 2 3 4 3
    //list3.foreach(println) // 8 9
    //list4.foreach(println) // 8 9 7 6 5 1 2 3 4 3
    list5.foreach(println)  // 1 2 3 4
  }
}

3.2 可变ListBuffer

1)说明
(1)创建一个可变集合ListBuffer
(2)向集合中添加数据
(3)打印集合数据

2)案例实操

import scala.collection.mutable.ListBuffer

object TestList {
  def main(args: Array[String]): Unit = {
    //(1)创建一个可变集合
    val buffer = ListBuffer(1,2,3,4)
    //(2)向集合中添加数据
    buffer.+=(5)
    //(3)打印集合数据
    buffer.foreach(println)
  }
}

四、set集合

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

4.1 不可变set

1)说明
(1)Set默认是不可变集合,数据无序
(2)数据不可重复
(3)遍历集合
2)案例实操

object TestSet {
  def main(args: Array[String]): Unit = {
    //(1)Set默认是不可变集合,数据无序
    val set = Set(1,2,3,4,5,6)
    //(2)数据不可重复
    val set1 = Set(1,2,3,4,5,6,3)
    //(3)遍历集合
    for(x<-set1){
      println(x)
    }
  }
}

输出:

5
1
6
2
3
4

4.2 可变mutable.Set

1)说明
(1)创建可变集合mutable.Set
(2)打印集合
(3)集合添加元素
(4)向集合中添加元素,返回一个新的Set
(5)删除数据

2)案例实操

import scala.collection.mutable

object TestSet {
  def main(args: Array[String]): Unit = {

    //(1)创建可变集合
    val set = mutable.Set(1,2,3,4,5,6)
    //(3)集合添加元素
    set += 8
    //(4)向集合中添加元素,返回一个新的Set
    val ints = set.+(9)
    println(ints)
    println("set2=" + set)

    //(5)删除数据
    set-=(5)

    //(2)打印集合
    set.foreach(println)
    println(set.mkString(","))
  }
}

五、Map集合

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

5.1 不可变Map

1)说明

(1)创建不可变集合Map
(2)循环打印
(3)访问数据
(4)如果key不存在,返回0

2)案例实操

object TestMap {
  def main(args: Array[String]): Unit = {
    // Map
    //(1)创建不可变集合Map
    val map = Map( "a"->1, "b"->2, "c"->3 )
    //(3)访问数据
    for (elem <- map.keys) {
      // 使用get访问map集合的数据,会返回特殊类型Option(选项):有值(Some),无值(None)
      println(elem + "=" + map.get(elem).get)
    }
    //(4)如果key不存在,返回0
    println(map.get("d").getOrElse(0))
    println(map.getOrElse("d", 0))
    //(2)循环打印
    map.foreach((kv)=>{println(kv)})
  }
}

输出:

a=1
b=2
c=3
0
0
(a,1)
(b,2)
(c,3)

5.2 可变Map

1)说明

(1)创建可变集合
(2)打印集合
(3)向集合增加数据
(4)删除数据
(5)修改数据

2)案例实操

import scala.collection.mutable.ArrayBuffer

object TestSet {

  def main(args: Array[String]): Unit = {
    //(1)创建可变集合
    val map = mutable.Map( "a"->1, "b"->2, "c"->3 )
    //(3)向集合增加数据
    map.+=("d"->4)
    // 将数值4添加到集合,并把集合中原值1返回
    val maybeInt: Option[Int] = map.put("a", 4)
    println(maybeInt.getOrElse(0))
    //(4)删除数据
    map.-=("b", "c")
    //(5)修改数据
    map.update("d",5)
    //(2)打印集合
    map.foreach((kv)=>{println(kv)})
  }
}

六、元组

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

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

2)案例实操
(1)声明元组的方式:(元素,元素2,元素3)
(2)访问元组
(3)Map中的键值对其实就是元组,只不过元组的元素个数为2,称之为对偶

object TestTuple {
  
  def main(args: Array[String]): Unit = {
    //(1)声明元组的方式:(元素,元素2,元素3)
    val tuple: (Int, String, Boolean) = (40,"bobo",true)
    //(2)访问元组
    //(2.1)通过元素的顺序进行访问,调用方式:_顺序号
    println(tuple._1)
    println(tuple._2)
    println(tuple._3)
    //(2.2)通过索引访问数据
    println(tuple.productElement(0))
    //(2.3)通过迭代器访问数据
    for (elem <- tuple.productIterator) {
      println(elem)
    }
    //(3)Map中的键值对其实就是元组,只不过元组的元素个数为2,称之为对偶
    val map = Map("a"->1, "b"->2, "c"->3)
    map.foreach(tuple=>{println(tuple._1 + "=" + tuple._2)})
  }
}

输出:

40
bobo
true
40
40
bobo
true
a=1
b=2
c=3

七、集合常用函数

7.1 基本属性和常用操作

1)说明
(1)获取集合长度
(2)获取集合大小
(3)循环遍历
(4)迭代器
(5)生成字符串
(6)是否包含

2)案例实操

object TestList {

  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
    //(1)获取集合长度
    println(list.length) // 7
    //(2)获取集合大小
    println(list.size) // 7
    //(3)循环遍历
    list.foreach(println) // 1 2 3 4 5 6 7
    //(4)迭代器
    for (elem <- list.iterator) {
      println(elem)
    }// 1 2 3 4 5 6 7
    //(5)生成字符串
    println(list.mkString(",")) //1,2,3,4,5,6,7
    //(6)是否包含
    println(list.contains(3)) // true
  }
}

7.2 衍生集合

1)说明
(1)获取集合的头head
(2)获取集合的尾(不是头就是尾)tail
(3)集合最后一个数据 last
(4)集合初始数据(不包含最后一个)
(5)反转
(6)取前(后)n个元素
(7)去掉前(后)n个元素
(8)并集
(9)交集
(10)差集
(11)拉链
(12)滑窗

2)案例实操

object TestList {

  def main(args: Array[String]): Unit = {

    val list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
    val list2: List[Int] = List(4, 5, 6, 7, 8, 9, 10)
    //(1)获取集合的头
    println(list1.head) // 1
    //(2)获取集合的尾(不是头的就是尾)
    println(list1.tail) // List(2, 3, 4, 5, 6, 7) 
    //(3)集合最后一个数据
    println(list1.last) // 7 
    //(4)集合初始数据(不包含最后一个)
    println(list1.init) // List(1, 2, 3, 4, 5, 6)
    //(5)反转
    println(list1.reverse) // List(7, 6, 5, 4, 3, 2, 1)
    //(6)取前(后)n个元素
    println(list1.take(3)) // List(1, 2, 3)
    println(list1.takeRight(3)) // List(5, 6, 7)
    //(7)去掉前(后)n个元素
    println(list1.drop(3)) // List(4, 5, 6, 7)
    println(list1.dropRight(3)) // List(1, 2, 3, 4)
    //(8)并集
    println(list1.union(list2)) // List(1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 9, 10)
    //(9)交集
    println(list1.intersect(list2)) // List(4, 5, 6, 7)
    //(10)差集
    println(list1.diff(list2)) // List(1, 2, 3)
    //(11)拉链 注:如果两个集合的元素个数不相等,那么会将同等数量的数据进行拉链,多余的数据省略不用
    println(list1.zip(list2)) // List((1,4), (2,5), (3,6), (4,7), (5,8), (6,9), (7,10))
    //(12)滑窗
    list1.sliding(2, 5).foreach(println) //List(1, 2) List(6, 7)
  }
}

sliding

  • 第一个参数的含义是几个元素组成一个List。
  • 第二个参数的含义可以理解为,每次List第一个元素相对上一个List的第一个元素移动的步数。

输出:

1
List(2, 3, 4, 5, 6, 7)
7
List(1, 2, 3, 4, 5, 6)
List(7, 6, 5, 4, 3, 2, 1)
List(1, 2, 3)
List(5, 6, 7)
List(4, 5, 6, 7)
List(1, 2, 3, 4)
List(1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 9, 10)
List(4, 5, 6, 7)
List(1, 2, 3)
List((1,4), (2,5), (3,6), (4,7), (5,8), (6,9), (7,10))
List(1, 2)
List(6, 7)

7.3 集合计算初级函数

1)说明

​ (1)求和
​ (2)求乘积
​ (3)最大值
​ (4)最小值
​ (5)排序

2)实操

object TestList {

  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 5, -3, 4, 2, -7, 6)
    //(1)求和
    println(list.sum)
    //(2)求乘积
    println(list.product)
    //(3)最大值
    println(list.max)
    //(4)最小值
    println(list.min)
    //(5)排序
    // (5.1)按照元素大小排序
    println(list.sortBy(x => x))
    // (5.2)按照元素的绝对值大小排序
    println(list.sortBy(x => x.abs))
    // (5.3)按元素大小升序排序
    println(list.sortWith((x, y) => x < y))
    // (5.4)按元素大小降序排序
    println(list.sortWith((x, y) => x > y))
  }
}

8
5040
6
-7
List(-7, -3, 1, 2, 4, 5, 6)
List(1, 2, -3, 4, 5, 6, -7)
List(-7, -3, 1, 2, 4, 5, 6)
List(6, 5, 4, 2, 1, -3, -7)

  • sorted

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

  • sortBy

对一个属性或多个属性进行排序,通过它的类型。

  • sortWith

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

7.4 集合计算高级函数

1)说明

(1)过滤:fliter

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

img

(2)转化/映射:map

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

img

(3)扁平化:flatten

用来压平,就是将多个集合展开,组合成新的一个集合。有点降维打击的意思?

img

(4)扁平化+映射

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

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

案例:

  1. 有一个包含了若干个文本行的列表:“hadoop hive spark flink flume”, “kudu hbase sqoop storm”
  2. 获取到文本行中的每一个单词,并将每一个单词都放到列表中

img

先map后flatten

// 定义文本行列表
scala> val a = List("hadoop hive spark flink flume", "kudu hbase sqoop storm")
a: List[String] = List(hadoop hive spark flink flume, kudu hbase sqoop storm)

// 使用map将文本行转换为单词数组
scala> a.map(x=>x.split(" "))
res5: List[Array[String]] = List(Array(hadoop, hive, spark, flink, flume), Array(kudu, hbase, sqoop, storm))

// 扁平化,将数组中的
scala> a.map(x=>x.split(" ")).flatten
res6: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)

使用flatMap简化操作

scala>  val a = List("hadoop hive spark flink flume", "kudu hbase sqoop storm")
a: List[String] = List(hadoop hive spark flink flume, kudu hbase sqoop storm)

scala> a.flatMap(_.split(" "))
res7: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)

(5)分组:groupby

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

(6)简化(规约):

(7)折叠:fold

2)实操

object TestList {

  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
    val nestedList: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
    val wordList: List[String] = List("hello world", "hello atguigu", "hello scala")

    //(1)过滤        // 选取偶数
    println(list.filter(x => x % 2 == 0))

    //(2)转化/映射
    println(list.map(x => x + 1))

    //(3)扁平化
    println(nestedList.flatten)

    //(4)扁平化+映射 注:flatMap相当于先进行map操作,在进行flatten操作
    println(wordList.flatMap(x => x.split(" ")))

    //(5)分组
    println(list.groupBy(x => x % 2))

  }
}    

List(2, 4, 6, 8)
List(2, 3, 4, 5, 6, 7, 8, 9, 10)
List(1, 2, 3, 4, 5, 6, 7, 8, 9)
List(hello, world, hello, atguigu, hello, scala)
Map(1 -> List(1, 3, 5, 7, 9), 0 -> List(2, 4, 6, 8))

3)Reduce方法

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

案例实操

object TestReduce {

  def main(args: Array[String]): Unit = {

    val list = List(1,2,3,4)
    // 将数据两两结合,实现运算规则
    val i: Int = list.reduce( (x,y) => x-y )
    // ((1-2)-3-4) = -8
    println("i = " + i)
    // 从源码的角度,reduce底层调用的其实就是reduceLeft
    //val i1 = list.reduceLeft((x,y) => x-y)
    // ((4-3)-2-1) = -2
    val i2 = list.reduceRight((x,y) => x-y)
    println(i2)
  }
}

输出:

i = -8
-2

4)Fold方法

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

(1)案例实操:fold基本使用

object TestFold {

  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4)
    // fold方法使用了函数柯里化,存在两个参数列表
    // 第一个参数列表为 : 零值(初始值)
    // 第二个参数列表为:
    // fold底层其实为foldLeft
    // 1是初始值   ((1-1)-2-3-4) = -9
    val i = list.foldLeft(1)((x,y)=>x-y)
    // 10是初始值   1-(2-(3-(10-4))) = 8
    val i1 = list.foldRight(10)((x,y)=>x-y)
    println(i)
    println(i1)
  }
}

输出:

-9
8

(2)案例实操:两个集合合并

object TestFold {
  def main(args: Array[String]): Unit = {
    // 两个Map的数据合并
    val map1 = mutable.Map("a"->1, "b"->2, "c"->3)
    val map2 = mutable.Map("a"->4, "b"->5, "d"->6)
    val map3: mutable.Map[String, Int] = map2.foldLeft(map1) {
      (map, kv) => {
        val k = kv._1
        val v = kv._2
        map(k) = map.getOrElse(k, 0) + v
        map
      }
    }
    println(map3)
  }
}

输出:

Map(b -> 7, d -> 6, a -> 5, c -> 3)

7.5 普通wordcount案例

1)需求

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

2)需求分析
img

3)案例实操

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

    // 1. 对字符串进行切分,得到一个打散所有单词的列表
    val wordList = stringList.flatMap(_.split(" "))
    println(wordList)

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

    // 3. 对分组之后的list取长度,得到每个单词的个数
    val countMap: Map[String, Int] = groupMap.map(kv => (kv._1, kv._2.length))
    println(countMap)

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

    println(sortList)
  }
}

输出:

List(hello, hello, world, hello, scala, hello, spark, from, scala, hello, flink, from, scala)

Map(world -> List(world), flink -> List(flink), spark -> List(spark), scala -> List(scala, scala, scala), from -> List(from, from), hello -> List(hello, hello, hello, hello, hello))

Map(world -> 1, flink -> 1, spark -> 1, scala -> 3, from -> 2, hello -> 5)

List((hello,5), (scala,3), (from,2))

7.6 复杂wordcount案例

案例实操

object ComplexWordCount {
  def main(args: Array[String]): Unit = {
    //二元组 在之前进行过预统计
    val tupleList: List[(String, Int)] = List(
      ("hello", 1),
      ("hello world", 2),
      ("hello scala", 3),
      ("hello spark from scala", 1),
      ("hello flink from scala", 2)
    )

    // 思路一:直接展开为普通版本
    // 但这样之前的工作白做了
    val newStringList: List[String] = tupleList.map(
      kv => {
        (kv._1.trim + " ") * kv._2
      }
    )
    println(newStringList)

    // 接下来操作与普通版本完全一致
    val wordCountList: List[(String, Int)] = newStringList
      .flatMap(_.split(" "))    // 空格分词
      .groupBy( word => word )     // 按照单词分组
      .map( kv => (kv._1, kv._2.size) )     // 统计出每个单词的个数
      .toList
      .sortBy(_._2)(Ordering[Int].reverse)
      .take(3)

    println(wordCountList)

    println("================================")

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

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

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

    // 4. 转换成list,排序取前3
    val countList = countMap.toList
      .sortWith(_._2 > _._2)
      .take(3)
    println(countList)
  }
}

输出:
================================
List((hello,1), (hello,2), (world,2), (hello,3), (scala,3), (hello,1), (spark,1), (from,1), (scala,1), (hello,2), (flink,2), (from,2), (scala,2))

Map(world -> List((world,2)), flink -> List((flink,2)), spark -> List((spark,1)), scala -> List((scala,3), (scala,1), (scala,2)), from -> List((from,1), (from,2)), hello -> List((hello,1), (hello,2), (hello,3), (hello,1), (hello,2)))

Map(world -> 2, flink -> 2, spark -> 1, scala -> 6, from -> 3, hello -> 9)

List((hello,9), (scala,6), (from,3))

八、队列

1)说明

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

2)案例实操

object TestQueue {

  def main(args: Array[String]): Unit = {
    val que = new mutable.Queue[String]()
    que.enqueue("a", "b", "c")
    println(que.dequeue())
    println(que.dequeue())
    println(que.dequeue())
  }
}

九、并行集合

1)说明

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

2)案例实操

object TestPar {
  def main(args: Array[String]): Unit = {
    val result1 = (0 to 100).map{case _ => Thread.currentThread.getName}
    val result2 = (0 to 100).par.map{case _ => Thread.currentThread.getName}
    println(result1)
    println(result2)
  }
}
posted @ 2021-12-28 17:52  王陸  阅读(313)  评论(0编辑  收藏  举报