• Scala入门到精通(尚硅谷学习笔记)章节九——集合


    集合简介

    (1)Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable特质。
    (2)对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两个包
    不可变集合:scala.collection.immutable
    可变集合: scala.collection.mutable
    (3)Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于 java 中的 String 对象
    在这里插入图片描述

    (4)可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象
    建议:在操作集合的时候,不可变用符号,可变用方法
    在这里插入图片描述

    Array数组

    不可变数组

    数组创建

    //方法一
    val arr1:Array[Int] = new Array[Int](5)
    
    //方法二
    val arr2 = Array(12,24,56,784,2)//省略了.apply
    
    • 1
    • 2
    • 3
    • 4
    • 5

    访问元素

        println(arr1(0))//0
        println(arr1(3))//0
        println(arr1(4))//0
        println(arr1(5))//error
    
    • 1
    • 2
    • 3
    • 4

    修改元素

    arr1(0) = 12
    
    • 1

    遍历数组

    //方法一
    for(i <- 0 until arr1.length){
      println(arr1(i))
    }
    
    //方法二(indices方法)
    for(i <- arr1.indices) println(arr1(i))
    
    //方法三(增强for循环)
    for(elem<- arr1) println(arr1(elem))
    
    //方法四(迭代器)
    while (iter.hasNext)
      println(iter.next())
    
    //方法五(调用foreach方法)
    arr1.foreach((elem;Int) => println(elem))
    arr1.foreach(println)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    添加元素(通过新数组返回)
    scala底层有这样一个规则

    val newArr = arr1.:+(73)//加在最后
    val newArr = arr1 :+ 73 
    println(newArr.mkString("--"))
    val newArr = arr1.+:(73)//加在最前
    val newArr2 = 73 +:65 +: arr1
    
    val newArr3 = 73 +:65 +: arr1 :+ 73 :+ 67
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    源代码如下
    在这里插入图片描述
    可以看到底层先创建了新数组,长度加一,将元素一一复制进新数组

    可变数组

    创建数组

    val arr1 = new ArrayBuffer[Int]()//此时arr1为空
    val arr2 =ArrayBuffer(23,67)
    
    • 1
    • 2

    访问数组

    println(arr1(0))//报错,数组越界
    println(arr2(0))//23
    
    
    • 1
    • 2
    • 3

    添加元素

    arr1 += 19//加在最后
    arr1.append(19)//加在最后
    77 +=:arr1//加在最前
    arr1.prepend(19)//加载最前
    arr1.insert(1,13,58)//在1索引位置添加13和58
    
    • 1
    • 2
    • 3
    • 4
    • 5

    删除元素

    //根据位置
    arr1.remove(0,6)//从索引为0的位置开始删除6个元素
    
    //根据特征删除
    arr1 -= 13//删除值为13的元素
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    可变数组转换为不可变数组

        val arr =ArrayBuffer(23,67)
        val newArr = arr.toArray
    
    • 1
    • 2

    不可变数组转换为可变数组

    val buffer = newArr.toBuffer
    
    • 1

    多维数组

    创建多维数组
    scala最高支持创建五维数组
    以创建2行3列的二维数组为例

    val array: Array[Array[Int]] = Array.ofDim[Int](2,3)
    
    • 1

    赋值并访问元素

    //赋值
    array(0)(2) = 10
    
    //访问
    array(0)(2)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    遍历

    //使用循环
    for (i <- array.indices; j <- array(i).indices){
    	println(array(i)(j))
    }
    
    //foreach
    array.foreach(line => line.foreach(println))
    array.foreach(_.foreach(println))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    List列表

    不可变列表

    Scala 列表类似于数组,它们所有元素的类型都相同,但是它们也有所不同:列表是不可变的,值一旦被定义了就不能改变,其次列表 具有递归的结构(也就是链接表结构)而数组不是。
    源代码为type List[+A] = cala.collection .immutable.List[A],可以看到Scala对List进行了重定义,immutable代表不可变的类型。

    创建列表
    首先查看List的源代码,sealed abstract class List[+A] extends AbstractSeq[A]代表它是一个抽象类,因此不能直接创建对象,而是使用名为List的伴生对象。override def apply[A](xs: A*): List[A] = xs.toList,其中xs是参数名,A是泛型,*表示可变长参数,最终是调用了toList方法转成了List

    val list1 = List(23,65,87)
    println(list1)
    
    • 1
    • 2

    遍历列表

    list1.foreach(println)
    
    • 1

    添加元素
    以一种方式与数组添加元素相同

    val list2 = list1.:+73
    val list3 = 10 +: list1
    
    • 1
    • 2

    scala的List实现的子类中还有双冒号的特殊子类,该子类的源代码为 def ::[B >: A] (x: B): List[B] =new scala.collection.immutable.::(x, this),传进来的值相当于放到了原列表的最前面,该方法主要应用场景主要是创建新列表并添加第一个值

    val list4 = Nil.::(31)
    //List(31)
    
    • 1
    • 2

    基于.的特性,我们可以将数字置前,从而省略.。该语句的含义是基于Nil从右往左依次在列表前面追加数字,最终得到的结果是顺序的

    val list5 = 17 :: 28 :: 59 ::78 ::Nil
    //List(17,28,59,78)
    
    • 1
    • 2

    合并列表
    scala使用三冒号对两个列表进行先拆分,在合并的操作。源代码如下:

    def :::[B >: A](prefix: List[B]): List[B] =
        if (isEmpty) prefix
        else if (prefix.isEmpty) this
        else (new ListBuffer[B] ++= prefix).prependToList(this)
    
    • 1
    • 2
    • 3
    • 4

    方法演示

    val list6 = list4 ::: list5
    //List(31, 17, 28, 59, 78)
    
    • 1
    • 2

    同时,++操作也能够合并两个列表,它实际上就是调用了:::方法

    val list7 = list4 ::: list5
    //List(31, 17, 28, 59, 78)
    
    • 1
    • 2

    可变列表

    创建列表
    可变列表的创建与可变数组的创建类似

        val list1 = new ListBuffer[Int]()//此时arr1为空
        val list2 =ListBuffer(23,67)
    
    • 1
    • 2

    添加元素

    list1.append(156)//加在最后
    list1.prepend(19)//加载最前
    list1.insert(1,19,22)//指定位置
    31 ==:90 +=: 300 +=: list1 += 25 += 49
    //ListBuffer(31, 90, 300, 19, 19, 22, 156, 25, 49)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    合并列表
    想要list1和list2合并,使用++操作。源代码为def ++(xs: GenTraversableOnce[A]): This = clone() ++= xs.seq,它将列表进行克隆,++会创建新缓存,++=从这个缓冲区添加一个元素并返回该缓冲区本身。

    list1 ++= list2
    val list3 = list1 ++ list2
    
    • 1
    • 2

    修改元素

    list2(3) = 30
    
    • 1

    该写法调用update方法,等价于list2.update(3,30)
    删除元素

    list2.remove(3)
    
    • 1

    Set集合

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

    不可变Set

    (1)Set 默认是不可变集合,数据无序
    (2)数据不可重复
    创建集合

        val set1 = Set(1, 23, 24, 33, 44, 33)
        println(set1)   //自动去除重复数据
        //HashSet(24, 1, 33, 44, 23)
    
    • 1
    • 2
    • 3

    添加元素

    val set2 = set1.+(20) //set1不变
    println(set2) //HashSet(24, 20, 1, 33, 44, 23) 无序
    
    val set3 = set1 + 56
    println(set3) //HashSet(56, 24, 1, 33, 44, 23)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    合并集合

    val set4 = Set(22, 45, 73, 97)
    val set5 = set2 ++ set4
    println(set5) //HashSet(24, 20, 1, 33, 97, 73, 45, 23, 22, 44)
    
    • 1
    • 2
    • 3

    删除元素

        val set6 = set2 - 20
        println(set6) //HashSet(24, 1, 33, 44, 23)
    
    • 1
    • 2

    可变Set

    引用scala.collection.mutable.Set
    创建集合

    val set1 = mutable.Set(13, 24, 57, 36)
    println(set1)  //HashSet(24, 57, 36, 13)
    
    • 1
    • 2

    添加元素
    +只会返回一个新的对象,set1本身并没有添加元素,因此需要创建新集合接收对象

    val set2 = set1+11
    
    • 1

    可以直接使用+=或者add方法,add方法调用+=并判断添加元素是否出现在原集合中

    println(set1)  //HashSet(24, 57, 36, 13)
    set1 +=111
    println(set1)  //HashSet(24, 57, 36, 13, 111)
    set1.add(88)
    
    • 1
    • 2
    • 3
    • 4

    删除元素
    删除操作和添加操作类似

    set1 -= 24
    set1.remove(57)
    println(set1) //HashSet(36, 88, 13, 111)
    
    • 1
    • 2
    • 3

    合并集合

    val set3 = mutable.Set(22, 89, 45, 20)
    val set4 = set1 ++ set3
    println(set4) //HashSet(20, 36, 22, 88, 89, 13, 45, 111)
    set1 ++= set3   //set1元素与set4相同
    
    • 1
    • 2
    • 3
    • 4

    Map集合

    不可变Map

    Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value)映射。
    创建Map
    Map在底层作为特质存在,因此不能直接在外部创建一个对象,而是用伴生对象直接传入数据

    val map1: Map[String, Int] = Map("a" -> 12, "b" -> 5, "hello" -> 3)
    println(map1)
    println(map1.getClass)//得到当前类的表达
    //Map(a -> 12, b -> 5, hello -> 3)
    //class scala.collection.immutable.Map$Map3
    
    • 1
    • 2
    • 3
    • 4
    • 5

    遍历元素
    底层具体逻辑为map1.foreach( (kv: (String, Int)) => println(kv) )

    map1.foreach(println)
    
    //(a,12)
    //(b,5)
    //(hello,3)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    取map中的所有key或者value

        for (key <- map1.keys) {
          println(s"$key ---> ${map1.get(key)}")
        }
        //a ---> Some(12)
        //b ---> Some(5)
        //hello ---> Some(3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    访问某一个key的value

    println(map1.get("a").get)
    println(map1("a"))
    
    • 1
    • 2

    如果传入的key不存在时,map1.get("a")将会返回None,此时再用get方法会报异常,因此使用getOrElse避免异常

    println(map1.getOrElse("c", 0)) //防止为空时get抛出异常   若为None返回0
    
    • 1

    可变map

    创建map

    val map1 = mutable.Map("a" -> 12, "b" -> 5, "hello" -> 3)
    println(map1)
    println(map1.getClass)
    //HashMap(a -> 12, b -> 5, hello -> 3)
    //class scala.collection.mutable.HashMap
    
    • 1
    • 2
    • 3
    • 4
    • 5

    添加元素

    map1.put("c", 4)
    map1.put("d", 8)
    println(map1)
    //HashMap(a -> 12, b -> 5, c -> 4, hello -> 3, d -> 8)
    
    • 1
    • 2
    • 3
    • 4

    进入put方法,能够看到调用了update方法。update方法底层实现源码为update(key: A, value: B) { this += ((key, value)) }。其中(key, value)表示键值对,省略括号,编译器会理解为传入两个参数。
    因此我们可以直接使用+=

    map1 += (("e", 4))
    
    • 1

    删除元素
    删除元素直接指定key就可以

    map1.remove("a")
    println(map1)  //HashMap(b -> 5, c -> 4, d -> 8, e -> 4, hello -> 3)
    map1 -= "hello"
    
    • 1
    • 2
    • 3

    修改元素
    key未出现的相当于添加

    map1("a") = 2  //未出现的相当于添加
    map1("b") = 4  //修改
    println(map1)  //HashMap(a -> 2, b -> 4, c -> 4, d -> 8, e -> 4)
    
    • 1
    • 2
    • 3

    合并Map
    map2中的元素添加到map1中,未出现过的直接添加,出现过的覆盖。
    不可变集合也可以与可变集合合并,但要赋值给新的不可变map

    val map2 = mutable.Map("d" -> 12, "b" -> 99, "k" -> 3)
    map1 ++= map2
    println(map1)  //HashMap(a -> 2, b -> 99, c -> 4, d -> 12, e -> 4, k -> 3)
    
    
    • 1
    • 2
    • 3
    • 4

    元组

    元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,将多个无关的数据封装为—个整体,称为元组。
    注意:元组中最大只能有 22 个元素。
    声明元组

    val tuple: (String, Char, Int, Boolean) = ("hello", 'a',  12, false) //类型需要一一对应
    
    • 1

    访问数据

    println(tuple._1) //hello
    println(tuple._2) //a
    println(tuple._3) //12
    
    • 1
    • 2
    • 3

    遍历元组

    for (elem <- tuple.productIterator) {println(elem)}  //依次打印
    
    • 1

    嵌套元组

    val mulTuple = (12, 0.9, (9, "h"), 20)
    println(mulTuple._3)
    //(9,h)
    
    • 1
    • 2
    • 3

    集合的基本属性和常用操作

    以下方法以ListSet为例,方法均通用

    val list = List(1, 2, 6, 34)
    val set = Set(23, 45, 1, 77)
    
    • 1
    • 2

    获取集合长度

    println(list.length)
    
    • 1

    获取集合大小

    println(set.size)
    
    • 1

    循环遍历

    for (elem <- list) {
      println(elem)
    }
    set.foreach(println)
    
    • 1
    • 2
    • 3
    • 4

    迭代器

    for (elem <- set.iterator) println(elem)
    
    • 1

    生成字符串

    println(list)  //List(1, 2, 6, 34)
    println(set)   //Set(23, 45, 1, 77)
    println(list.mkString("--"))   //1--2--6--34
    
    • 1
    • 2
    • 3

    是否包含

    println(list.contains(2))  //true
    println(set.contains(3))   //false
    
    • 1
    • 2

    集合衍生操作

    val list1 = List(1, 2, 6, 34, 99)
    val list2 = List(33, 2, 65, 34, 78)
    
    • 1
    • 2

    单集合操作

    获取集合的头

    println(list1.head)   //1
    
    • 1

    获取集合的尾
    不是头的就是尾,得到的是新的list,只去除了第一个值

    println(list1.tail)   //List(2, 6, 34, 99)
    
    • 1

    获取集合最后一个数据

    println(list1.last)   //99
    
    • 1

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

    println(list1.init)  //List(1, 2, 6, 34)
    
    • 1

    反转
    底层的代码为while (!these.isEmpty) { result = these.head :: result these = these.tail,即进行head叠加操作

    println(list1.reverse)  //List(99, 34, 6, 2, 1)
    
    • 1

    取前(后)n 个元素

        println(list1.take(3))  //前3个
        println(list1.takeRight(3)) //后3个
    
    • 1
    • 2

    去掉前(后)n 个元素

    println(list1.drop(1))   //去掉前n个
    println(list2.dropRight(1))  //去掉后n个
    
    • 1
    • 2

    双集合操作

    并集(union)

    val union = list1.union(list2)
    println("union " + union)
    println(list1 ::: list2)
    //union List(1, 2, 6, 34, 99, 33, 2, 65, 34, 78)
    //List(1, 2, 6, 34, 99, 33, 2, 65, 34, 78)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意:set合并会去重

    val set1 = Set(1,3,5,7,2,89)
    val set2 = Set(3,7,2,45,4,8,19)
    val union2 = set1.union(set2)
    //union2: Set(5,89,1,2,45,7,3,8,19,4)
    
    • 1
    • 2
    • 3
    • 4

    交集(intersect)

        val intersection = list1.intersect(list2)
        println("intersection " + intersection)
        //intersection List(2, 34)
    
    • 1
    • 2
    • 3

    差集

    val diff1 = list1.diff(list2)
    val diff2 = list2.diff(list1)
    println("diff1 " + diff1)
    //diff1 List(1, 6, 99)
    println("diff2 " + diff2)
    //diff2 List(33, 65, 78)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    拉链
    两个集合类型对应位置的元素分别配对形成二元组,多出的单个元素直接去除

        println(list1.zip(list2)) //一一对应形成二元组,多余的不输出
        //List((1,33), (2,2), (6,65), (34,34), (99,78))
    
    • 1
    • 2

    滑窗
    输出list1.sliding(3),发现是迭代器,使用循环遍历
    源代码为def sliding(size: Int, step: Int): Iterator[Repr],第一个参数为窗口大小,第二个参数为滑动步长

    println(list1.sliding(3).foreach(println))
    //List(1, 2, 6)
    //List(2, 6, 34)
    //List(6, 34, 99)
    //()
    println(list1.sliding(3, 2).foreach(println))  //窗口长度,步长
    //窗口长度和步长相同就形成了滚动窗口
    //List(1, 2, 6)
    //List(6, 34, 99)
    //()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    集合计算简单函数

    创建一个列表进行演示

    val list = List(21, 4, 65, 2, -7)
    
    • 1

    求和

    println(list.sum)
    
    • 1

    求乘积

    println(list.product)
    
    • 1

    最大值

    println(list.max)
    
    • 1

    此时如果有一个列表中的元素为("a", 3), ("b", 1), ("d", 9), ("f", 10),再使用max函数,它会从元组的第一个元素中找到最大值,如果希望找到元组的第二个元素的最大值,使用到maxBy函数

    println(list2.maxBy((tuple: (String, Int)) => tuple._2)) //(f,10)  指定按第二个元素排序
    println(list2.maxBy( _._2) ) //(f,10)
    
    • 1
    • 2

    最小值

    println(list.min)
    println(list2.minBy(_._2))
    
    • 1
    • 2

    排序
    默认从小到大

       val sortedList = list.sorted
       println(sortedList)   //List(-7, 2, 4, 21, 65)
    
    • 1
    • 2

    使用隐式参数进行从大到小

    println(list.sorted(Ordering[Int].reverse))
    println(list2.sorted)  //按第一个元素
    
    • 1
    • 2

    如何对list2这种列表进行排序?使用sortBy方法

    println(list2.sortBy(_._2)) //List((b,1), (a,3), (d,9), (f,10))
    println(list2.sortBy(_._2)(Ordering[Int].reverse)) //List((f,10), (d,9), (a,3), (b,1))
    
    • 1
    • 2

    同时,排序还可以使用sortWith方法,直接把规则传入

    println(list.sortWith( (a: Int, b: Int) => {a < b}))  //从小打到排序
    println(list.sortWith( _ < _ )) //从小到大排序
    println(list.sortWith(( _ > _))) //从大到小排序
    
    • 1
    • 2
    • 3

    集合计算高级函数

    map类

    创建新列表

    val list = List(1, 2, 3, 4, 5, 6, 7, 8)
    
    • 1

    过滤
    遍历一个集合并从中获取满足指定条件的元素组成一个新的集合。
    例如:选取列表中的偶数

    val evenList = list.filter( (elem: Int) => {elem % 2 == 0} )
    println(evenList)   //List(2, 4, 6, 8)
    //化简后
    println(list.filter( _ % 2== 0)) //选取偶数
    println(list.filter( _ % 2== 1)) //选取奇数
    
    • 1
    • 2
    • 3
    • 4
    • 5

    转化/映射(map)
    将集合中的每一个元素映射到某一个函数
    源代码final override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That 将数据类型A转换数据类型B。

    println(list.map( _ * 2))  //List(2, 4, 6, 8, 10, 12, 14, 16)
    println(list.map( x => x * x))  //两个相同的x不可省略
    
    • 1
    • 2

    扁平化
    扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten 操作集合中的每个元素的子元素映射到某个函数并返回新集合

    val nestedList: List[List[Int]] = List(List(1,2,3), List(4,5,6), List(7,8,9))
    val flatList2 = nestedList.flatten
    println(flatList2) //List(1, 2, 3, 4, 5, 6, 7, 8, 9)
    
    • 1
    • 2
    • 3

    扁平映射
    在实际需求中,可能会遇到需要用map进行映射,再去进行扁平化的操作。
    例:将一组字符串进行分词,并保存成单词的列表

        val wordList: List[String] = List("hello world", "hello scala", "hello java")
        val splitList: List[Array[String]] = wordList.map( _.split(" "))//通过空格进行分词
        val flattenList = splitList.flatten//扁平化操作
        println(flattenList) //List(hello, world, hello, scala, hello, java)
    
    • 1
    • 2
    • 3
    • 4

    扁平映射可以简化上述两步操作

    val flatMapList = wordList.flatMap(_.split(" "))
    println(flatMapList) //List(hello, world, hello, scala, hello, java)
    
    • 1
    • 2

    分组(group)
    按照指定的规则对集合的元素进行分组
    例:分成奇偶两组

    val groupMap: Map[Int, List[Int]] = list.groupBy( _ % 2 )
    val groupMap2: Map[String, List[Int]] = list.groupBy( data => if (data % 2 == 0) "偶数" else "奇数" )
    
    println(groupMap) //HashMap(0 -> List(2, 4, 6, 8), 1 -> List(1, 3, 5, 7))
    println(groupMap2) //HashMap(偶数 -> List(2, 4, 6, 8), 奇数 -> List(1, 3, 5, 7))
    
    val wordList2 = List("China", "alice", "cary", "bob", "america", "canada")
    println(wordList2.groupBy( _.charAt(0) )) //按首字母
    //HashMap(a -> List(alice, america), b -> List(bob), C -> List(China), c -> List(cary, canada))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    reduce类

    简化(归约)
    scala当中的reduce可以对集合当中的元素进行归约(将同一集合中的元素进行聚合)操作。
    reduce底层调用的就是reduceLeft,集合中各元素从左至右依次两两聚合。
    reduceRight的源代码为def reduceRight[B >: A](op: (A, B) => B): B = if (isEmpty) throw new UnsupportedOperationException("Nil.reduceRight") else if (tail.isEmpty) head else op(head, tail.reduceRight(op)),它会先判断集合是否为空,接着判断尾部是否为空,为空返回头部元素,不为空就进行递归操作,最终呈现的效果是从右往左归约。

    println(list.reduce( _ + _))  // 10
    println(list.reduceLeft( _ + _ )) //10
    println(list.reduceRight( _ + _ )) //10
    
    val list2 = List(3, 4, 5, 8, 10)
    println(list2.reduce( _ -_ )) //3-4-5-8-10 -24
    println(list2.reduceLeft( _ -_ )) // -24  从左向右减
    println(list2.reduceRight(_ - _ )) // 3 - ( 4 - ( 5 - ( 8 - ( 10))) ) = 6 底层是递归调用的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    折叠(fold)
    fold底层调用的就是foldLeft,作用是将一种格式的输入数据转化成另外一种格式返回。源代码为 def foldLeft[B](z: B)(op: (B, A) => B): B = { var result = z this foreach (x => result = op(result, x)) result },聚合状态可以和当前元素的状态不同,apply方法调用了op操作,把resultx进行聚合,把结果返回给变量result

    println(list.fold(10)(_ + _)) //10 + 1 + 2 + 3 - 4  20
    println(list.foldLeft(10)(_ - _)) //10 - 1 - 2 - 3 - 4  0
    println(list2.foldRight(11)(_ -_)) // 3 - (4 - (5 - (8 - (10 - 11))))
    
    • 1
    • 2
    • 3

    简单wordcount案例
    定义两个Map集合,map1和map2代表分别两次字母频次的统计。因此,需求应当是如果key不在基准map中,直接添加;如果不在基准map中,则需要将value进行叠加,再进行更新。

    val map1 = Map("a" -> 2, "b" -> 4, "c" -> 3)
    val map2 = mutable.Map("a" -> 4, "b" -> 1, "c" -> 2, "d" -> 9)
    
    val map3 = map1.foldLeft(map2)(  //这里只能用foldLeft 两个不同值进行fold
      (mergedMap, kv) => {   //第一个参数表示合并后的结果,第二个参数是元素
    
    //取出kv键值对
        val key = kv._1
        val value = kv._2
    
    //判断是否在mergedMap中,不在就赋初始值0
        mergedMap(key) = mergedMap.getOrElse(key, 0) + value  //查找出现过的,加起来
        mergedMap
      }
    )
    println(map3)
    //mutable类型
    //HashMap(a -> 6, b -> 5, c -> 5, d -> 9)
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果。
    一开始输入进来的是多个语句列表,首先应当按照空格将单词进行切割,其次对每一种单词进行分组,分组结束统计每一组的个数,最后进行排序取出最多的三组计数结果。

        val stringList: List[String] = List(
          "hello",
          "hello world",
          "hello scala",
          "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.对分组之后的列表取长度,得到每个单词的个数(单词作为key,长度变为value)
        val countMap: Map[String, Int] = groupMap.map(kv => (kv._1, kv._2.length))
    
        //4.将map转换为list,排序取前三
        val sortList: List[(String, Int)] = countMap.toList
          //从大到小排序
          .sortWith(_._2 >_._2)
          //取前三
          .take(3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    复杂wordcount案例
    在复杂词频统计中,给出的列表不再是多个语句,二是多个语句出现的频次(进行了预统计)。
    具体步骤为:
    1.把所有的元组按照单词拆开跟句子的统计次数组合成一个元组
    2.对二元组按照单词进行分组
    3.叠加每个单词预统计的个数值
    4.转换成list,排序取前三

    val tupleList: List[(String,Int)] = List(
      ("hello", 1),
      ("hello world", 2),
      ("hello scala", 3),
      ("hello spark from scala", 1),
      ("hello flink from scala", 2)
    )
    
    //1.把所有的元组按照单词拆开跟句子的统计次数组合成一个元组
    val preCountList: List[(String,Int)] = tupleList.flatMap(
      tuple =>{
        //把字符串按空格进行切分
        val strings: Array[String] = tuple._1.split(" ")
        //把单词和统计数字组合成元组
        strings.map(word =>(word,tuple._2))
      }
    )
    
    //2.对二元组按照单词进行分组
    val preCountMap: Map[String, List[(String, Int)]] = preCountList.groupBy(_._1)
    
    //3.叠加每个单词预统计的个数值
    val countMap: Map[String, Int] = preCountMap.mapValues(
      tupleList => tupleList.map(_._2).sum
    )
    
    //4.转换成list,排序取前三
    val countList = countMap.toList
      .sortWith(_._2 >_._2)
      .take(3)
    println(countList)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    队列

    队列:操作受限的线性表,特点是先进先出,可以看作是特殊的序列。
    可变队列

    //创建一个可变队列
    val queue: mutable.Queue[String] = new mutable.Queue[String]()
    //入队
    queue.enqueue("a", "b", "c")
    println(queue)  //Queue(a, b, c)
    
    //出队
    println(queue.dequeue()) //a
    println(queue)  //Queue(b, c)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    不可变队列

    import scala.collection.immutable.Queue
    //创建一个不可变队列
    val queue2:Queue[String] = Queue("a", "b", "c")
    queue2.enqueue("d")
    println(queue2)  //Queue(a, b, c)  并未改变
    val queue3 = queue2.enqueue("d")
    println(queue3)  //Queue(a, b, c, d)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    并行集合

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

        //单线程
        val result  = (1 to 100).map(
          
          //输出ID都相同
          x => Thread.currentThread.getId
        )
        println(result)
        //Vector(1, 1, 1, ……)
    
        //并行计算
        val result2 = (1 to 100).par.map(
          
          //输出线程ID,发现不同线程在处理
          x => Thread.currentThread.getId
        )
        println(result2)
        //ParVector(20, 20, 20, 20, 30, ……) 由不同线程执行
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    【阿里云系列】-部署ACK集群的POD应用日志如何集成到日志服务(SLS)中
    JVM面试重点-1
    Vue(第十七课)AXIOS对JSON数据的增删改查
    wpf窗体背景添加径向渐变效果实现
    Redis 集群
    vue ant DatePicker 日期选择器 限制日期可控范围
    世界级黑客丨电脑犯罪界的汉尼拔
    【香橙派AIPro+opencv】基础数据结构、颜色转换函数和颜色空间
    这可是全网eNSP安装最完整,最详细的图解,没有之一(常见问题)
    deckGL自定义图层学习笔记
  • 原文地址:https://blog.csdn.net/weixin_47726676/article/details/126275838