Scala(七)集合

7.1 集合简介

  1说明

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

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

      不可变集合:scala.collection.immutable

      可变集合:  scala.collection.mutable

  2案例实操

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

    (2)可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。

package com.yuange.scala.day04

import scala.collection.mutable.ListBuffer

object TestListOne {
  def main(args: Array[String]): Unit = {
    //不可变List
    val testList: List[Int] = List(1,3,5,23,2)
    println(testList)
    //对不可变的List进行修改,在头部添加一个元素0
    val testList2 = 0 +: testList
    println(testList2)

    //可变List
    val testList3: ListBuffer[Int] = ListBuffer(1,3,5,7,4)
    println(testList3)
    //对可变list进行修改,在头部添加一个元素0
    val testList4 = 0 +: testList3
    println(testList4)
  }
}

7.1.1 不可变集合继承图

  1SetMapJava中也有的集合

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

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

  4String也是属于IndexeSeq

  5)我们发现经典的数据结构比如QueueStack被归属到LinerSeq

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

  7IndexSeqLinearSeq的区别:

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

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

7.1.2 可变集合继承图

7.2 数组

7.2.1 不可变数组

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

val arr1 = new Array[Int](10)

    (1new是关键字

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

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

  2)案例实操

package com.yuange.scala.day04

object TestArray {
  def main(args: Array[String]): Unit = {
    //定义数组
    val testArray = new Array[Int](4)
    println(testArray.length)
    //数组赋值
    testArray(2) = 100      //修改某个元素的值
    testArray.update(0,200) //采用方法的形式给数组赋值
    //遍历数组
    println(testArray.mkString(","))  //查看数组
    for (i <- testArray){   //普通遍历
      print(i + "\t")
    }
    println()
    //简化遍历
    def ergodic(i: Int): Unit = {
      println(i)
    }
//    testArray.foreach(ergodic)
//    testArray.foreach((i)=>{println(i)})  //简化
//    testArray.foreach(i=>println(i))
//    testArray.foreach(println(_))
    testArray.foreach(println)

    //增加元素:由于创建的是不可变数组,所以是在产生新数组
    println("------------------------")
    println(testArray.mkString(","))
    val ints = testArray :+ 5
    println(ints.mkString(","))
  }
}

  3)种方式定义数组

val arr1 = Array(1, 2)

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

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

  4案例实操

package com.yuange.scala.day04

object TestArrayTwo {
  def main(args: Array[String]): Unit = {
    var testArray = Array("zhansan","李四","王五")
    for (i <- testArray){
      println(i)
    }
  }
}

7.2.2 可变数组

  1)定义变长数组

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

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

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

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

  2)案例实操

    (1ArrayBuffer是有序的集合

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

package com.yuange.scala.day04

import scala.collection.mutable.ArrayBuffer

object TestArrayBuffer {
  def main(args: Array[String]): Unit = {
    //创建并赋值可变数组
    val testBuffer = ArrayBuffer[Any](1,2,3)
    //遍历数组
    for (i <- testBuffer){
      println(i)
    }
    println("length=" + testBuffer.length)
    println("hash=" + testBuffer.hashCode())
    //增加元素
    testBuffer.+=(4)  //追加数据
    println(testBuffer)
    testBuffer.append(5)  //想数组末尾添加数据
    println(testBuffer)
    testBuffer.insert(3,6,7)  //在角标为3的位置插入6和7,即插入之后6的角标为3,7的角标为4,角标从0开始计算
    println(testBuffer)
    println("hash=" + testBuffer.hashCode())  //hashCode不一致
    //修改元素
    testBuffer(0) = 100   //修改第一个元素的值
    println("*"*100)
    for (i <- testBuffer){
      println(i)
    }
    println("length=" + testBuffer.length)
  }
}

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

  1说明

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

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

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

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

  2案例实操

package com.yuange.scala.day04

import scala.collection.mutable.ArrayBuffer

object TestArrayBufferTwo {
  def main(args: Array[String]): Unit = {
    //创建一个空的可变数组
    val testBuffer = ArrayBuffer[Int]()
    //追加值
    testBuffer.append(1,2,3)
    println(testBuffer)
    //转不可变数组
    val newArray = testBuffer.toArray  //返回的结果是一个新的定长数组集合且原数组集合没有变化
    println("不可变数组=" + newArray)
    //转可变数组
    val newBuffer = newArray.toBuffer   //返回一个变长数组且原数组无任何变化,依然是定长数组
    newBuffer.append(100)
    println(newBuffer)
  }
}

7.2.4 多维数组

  1)多维数组定义(二维数组中有三个一维数组,每个一维数组中有四个元素)

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

  2)案例实操

package com.yuange.scala.day04

object DimArray {
  def main(args: Array[String]): Unit = {
    //创建一个二维数组,有三个元素,这三个元素中的每个元素含有四个元素
    var testDim = Array.ofDim[Int](3,4)
    testDim(1)(2) = 100   //给第二行的第三列元素进行修改,数组脚标从0开始
    //遍历二维数组
    for (i <- testDim){
      for (j <- i){
        print(j + "\t")
      }
      println()
    }
  }
}

7.3 Seq集合(List

7.3.1 不可变List

  1说明

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

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

    (4List增加数据

    (5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化
    (6)取指定数据
    (7)空集合Nil

  2案例实操

package com.yuange.scala.day04

object TestList {
  def main(args: Array[String]): Unit = {
    //List默认是不可变集合,创建一个List(数据有序,可重复)
    val testList: List[Int] = List(1,2,3,4,5)
    println("testList=" + testList)
    //空集合Nil
    val testList2 = 1 :: 2 :: 3 :: 4 :: 5 :: Nil
    println("testList2=" + testList2)
    //增加数据
    val testList3 = 6 :: testList //::的运算规则是从右到左
    println("testList3=" + testList3)
    val testList4 = 7 :: 8 :: 9 :: testList3  //将7,8,9插入到集合前面
    println("testList4=" + testList4)
    val testList5 = testList4.+:(10)    //将10插入到集合的第0位置
    println("testList5=" + testList5)
    //集合间合并,将一个整体拆分为一个个体,扁平化
    val testList6 = List(11,12)
    println("testList6=" + testList6)
    val testList7 = testList6 :: testList //::将testList6整个集合当成一个整体插入到testList集合前面
    println("testList7=" + testList7)
    val testList8 = testList6 ::: testList
    println("testList8=" + testList8)   //:::将testList6集合拆分成一个个个体然后插入到testList集合前面
    //取指定数据
    println("testList(3)=" + testList(3))
    //遍历List集合
    testList8.foreach(println)
  }
}

7.3.2 可变ListBuffer

  1说明

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

    (2)向集合中添加数据

    (3)打印集合数据

  2案例实操

package com.yuange.scala.day04

import scala.collection.mutable.ListBuffer

object TestListTwo {
  def main(args: Array[String]): Unit = {
    //创建可变集合
    val testBuffer = ListBuffer(1,2,3,4,5)
    //向集合中添加数据
    testBuffer.+=(6)  //添加数据在集合后面
    testBuffer.+=:(7)  //添加数据在集合前面
    //打印
    testBuffer.foreach(println)
  }
}

7.4 Set集合

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

7.4.1 不可变Set

  1)说明

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

    (2)数据不可重复

    (3)遍历集合

  2案例实操

package com.yuange.scala.day04

object TestSet {
  def main(args: Array[String]): Unit = {
    //set默认是不可变集合,数据无序
    val testSet = Set(1,3,5,7,9)
    println("testSet=" + testSet)
    //数据不可重复
    val testSet2 = Set(1,1,2,4,5,9);
    println("testSet2=" + testSet2)
  }
}

7.4.2 可变mutable.Set

  1说明

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

    (2)打印集合

    (3)集合添加元素

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

    (5)删除数据

  2案例实操

package com.yuange.scala.day04

import scala.collection.mutable

object TestSetTwo {
  def main(args: Array[String]): Unit = {
    //创建可变集合
    val testSet = mutable.Set(1,2,3,4)
    println("testSet=" + testSet)
    //向集合中添加元素
    testSet += 5
    println("testSet=" + testSet)
    //向集合中添加元素,返回一个新的set
    val testSet2 = testSet.+(6)
    println("testSet2=" + testSet2)
    //删除数据
    testSet2 -= 5
    //遍历集合
    testSet2.foreach(println)
    //打印集合并按,分割
    println(testSet2.mkString(","))
  }
}

7.5 Map集合

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

7.5.1 不可变Map

  1说明

    (1)创建不可变集合Map

    (2)循环打印

    (3)访问数据

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

  2案例实操

package com.yuange.scala.day04

object TestMap {
  def main(args: Array[String]): Unit = {
    //创建不可变集合Map
    val testMap = Map("zhangsan"->1001,"lisi"->1002,"wangwu"->1003)
    //访问数据
    for (elem <- testMap.keys){
      //使用get访问map集合中的数据,会返回特殊类型Option(选项):有值(Some),无值(None)
      println(elem + "=" + testMap.get(elem).get)
    }
    //若key不存在,返回0
    println(testMap.get("zhaoliu").getOrElse(0))
    println(testMap.getOrElse("zhaoliu",0))
    //循环打印
    testMap.foreach((kv)=>{println(kv)})
    testMap.foreach(kv=>{println(kv)})
  }
}

7.5.2 可变Map

  1说明

    (1)创建可变集合

    (2)打印集合

    (3)向集合增加数据

    (4)删除数据

    (5)修改数据

  2案例实操

package com.yuange.scala.day04

import scala.collection.mutable

object TestMapTwo {
  def main(args: Array[String]): Unit = {
    //创建可变集合
    val testMap = mutable.Map("zhangsan"->2001,"lisi"->2002,"wangwu"->2003)
    //向集合增加数据
    testMap.+=("zhaoliu"->2004)
    println("testMap=" + testMap)
    //将数值2005添加到集合,并把集合中原值2001返回
    val maybeInt: Option[Int] = testMap.put("zhangsan",2005)
    println(maybeInt.getOrElse(0))
    //删除数据
    testMap.-=("wangwu","lisi")
    println("删除数据之后:" + testMap)
    //修改数据
    testMap.update("zhaoliu",2006)
    println("修改数据之后:" + testMap)
    //打印集合
    testMap.foreach(kv=>{println(kv)})
  }
}

7.6 元组

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

  2案例实操

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

    (2)访问元组

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

package com.yuange.scala.day04

object TestTuple {
  def main(args: Array[String]): Unit = {
    //声明元组的方式:(元素1,元素2,元素3,...)
    val testTuple: (Int,String,Boolean) = (1001,"张三",true)
    //通过元素的顺序访问元组,调用方式:元组名称._顺序号
    println("testTuple._1=" + testTuple._1 + ",testTuple._2=" + testTuple._2 + ",testTuple._3=" + testTuple._3)
    //通过索引访问数据
    println("testTuple.productElement(0)=" + testTuple.productElement(0))
    //通过迭代器访问数据
    for (elem <- testTuple.productIterator){
      println(elem)
    }
    //Map中的键值对就是元组,只不过元素的个数为2,称之为对偶
    val testMap = Map("张三"->3001,"李四"->3002,"王五"->3003)
    testMap.foreach(kv=>{println(kv._1 + "=" + kv._2)})
  }
}

7.7 集合常用函数

7.7.1 基本属性和常用操作

  1说明

    (1)获取集合长度

    (2)获取集合大小

    (3)循环遍历

    (4)迭代器

    (5)生成字符串

    (6)是否包含

  2案例实操

package com.yuange.scala.day04

object Aggregate {
  def main(args: Array[String]): Unit = {
    val testList: List[Int] = List(1,3,5,7,9,11,13)
    //获取集合长度
    println("testList.length=" + testList.length)
    //获取集合大小
    println("testList.size=" + testList.size)
    //循环遍历
    testList.foreach(println)
    //迭代器
    for (i <- testList){
      println(i)
    }
    //生成字符串
    println(testList.mkString(","))
    //是否包含
    println(testList.contains(5))
  }
}

7.7.2 衍生集合

  1)说明

    (1)获取集合的头head

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

    (3)集合最后一个数据 last

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

    (5)反转

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

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

    (8)并集

    (9)交集

    (10)差集

    (11)拉链

    (12)滑窗

  2)案例实操

package com.yuange.scala.day04

object AggregateTwo {
  def main(args: Array[String]): Unit = {
    val testList: List[Int] = List(1,2,3,4,5,6,7)
    val testList2: List[Int] = List(4,5,6,7,8,9,10,11)
    //获取集合的头
    println("testList.head=" + testList.head)
    //获取集合的尾
    println("testList.tail=" + testList.tail)
    //集合最好一个数据
    println("testList.last=" + testList.last)
    //集合初始数据(不包含最后一个)
    println("testList.init=" + testList.init)
    //反转
    println("testList.reverse=" + testList.reverse)
    //取前n个元素
    var n = 3
    println(testList.take(n))
    //取后n个元素
    println(testList.takeRight(n))
    //去掉前n个元素
    println(testList.drop(n))
    //去掉后n个元素
    println(testList.dropRight(n))
    //并集
    println(testList.union(testList2))
    //交集
    println(testList.intersect(testList2))
    //差集
    println(testList.diff(testList2))
    //拉链:若两个集合的元素个数不相等,则将同等数量的数据进行拉链,多余的数据省略不用
    println(testList.zip(testList2))
    //滑窗:从第五个位置位置开始取两个数
    testList.sliding(2,5).foreach(println)
  }
}

7.7.3 集合计算初级函数

  1)说明

    (1)求和

    (2)求乘积

    (3)最大值

    (4)最小值

    (5)排序

  2)实操

package com.yuange.scala.day04

object AggregateThree {
  def main(args: Array[String]): Unit = {
    val testList: List[Int] = List(1,3,-5,-7,9,-11)
    //求和
    println("testList.sum=" + testList.sum)
    //求乘积
    println("testList.product=" + testList.product)
    //求最大值
    println("testList.max=" + testList.max)
    //求最小值
    println("testList.min=" + testList.min)
    //按元素大小排序:升序
    println(testList.sortBy(x => x))
    //按元素的绝对值大小排序
    println(testList.sortBy(x => x.abs))
    //按元素大小升序排序
    println(testList.sortWith((x,y) => x < y))
    //按元素大小降序排序
    println(testList.sortWith((x,y) => x > y))
  }
}

7.7.4 集合计算高级函数

  1)说明

      1)过滤

      2)转化/映射

      3)扁平化

      4)扁平化+映射 注:flatMap相当于先进行map操作,在进行flatten操作

      5)分组

      6)简化(规约)

      7)折叠

  2)实操

package com.yuange.scala.day04

object AggregateFour {
  def main(args: Array[String]): Unit = {
    val testList: 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 yuange","hello scala")

    //过滤
    println(testList.filter(x => x % 2 == 0))
    //转化/映射
    println(testList.map(x => x + 1))
    //扁平化
    println("nestedList.flatten=" + nestedList.flatten)
    //扁平化+映射:flatMap相当于先进行map操作,再进行flatten操作
    println("扁平化+映射=" + wordList.flatMap(x => x.split(" ")))
    //分组
    println(testList.groupBy(x => x % 2))
  }
}

  3)Reduce方法

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

package com.yuange.scala.day04

object TestReduce {
  def main(args: Array[String]): Unit = {
    val testList: List[Int] = List(1,2,3,4,5)
    //将数据两两结合,实现运算
    val i: Int = testList.reduce((x,y) => x - y)
    println("i=" + i)
    //从源码的角度,reduce底层调用的其实就是reduceLeft
//    val i2: Int = testList.reduce((x,y) => x - y)
    //((5-4)+(3-2)+1) = 3
    val i3 = testList.reduceRight((x,y) => x - y)
    println("i3=" + i3)
  }
}

  4)Fold方法

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

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

package com.yuange.scala.day04

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

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

package com.yuange.scala.day04

import scala.collection.mutable

object TestFoldTwo {
  def main(args: Array[String]): Unit = {
    val map = mutable.Map("zhangsan"->1001,"lisi"->1002,"wangwu"->1003)
    val map2 = mutable.Map("zhangsan"->1004,"lisi"->1005,"zhaoliu"->1006)

    val map3: mutable.Map[String,Int] = map2.foldLeft(map){
      (map,kv) => {
        val k = kv._1
        val v = kv._2
        map(k) = map.getOrElse(k,0) + v
        map
      }
    }
    println(map3)
  }
}

7.7.5 普通WordCount案例

  1需求

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

  2)需求分析

  3案例实操

package com.yuange.scala

object TestWordCount {
  def main(args: Array[String]): Unit = {
    //单词计数:将集合中出现的相同单词,进行计数,取计算排名前三的结果
    val testList = List("Hello Scala Hbase kafka", "Hello Scala Hbase", "Hello Scala", "Hello")
    //将每个字符串按空格进行切分并将切分好的单词放入List集合
    val str: List[String] = testList.flatMap(x => x.split(" "))
    //将相同的单词放在一起(分组)
    val str2: Map[String,List[String]] = str.groupBy(x => x)
    //对相同的单词进行计算
    val str3: Map[String,Int] = str2.map(x => (x._1,x._2.size))
    //对结果进行降序排序
    var sortList: List[(String,Int)] = str3.toList.sortWith{
      (left,right) => {
        left._2 > right._2
      }
    }
    //对排序后的结果取前三
    val result: List[(String,Int)] = sortList.take(3)
    println(result)
  }
}

7.7.6 复杂WordCount案例

  1方式一

  2案例实操

package com.yuange.scala.day04

object TestWordCounTwo {
  def main(args: Array[String]): Unit = {
    val testList = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1))
    val testList2: List[String] = testList.map(x => (x._1 + " ")*x._2)
    println("testList2=" + testList2)
    val word: List[String] = testList2.flatMap(_.split(" "))
    println("word=" + word)
    val groupMap: Map[String,List[String]] = word.groupBy(str => str)
    println("groupMap=" + groupMap)
    val number: Map[String,Int] = groupMap.map(i => (i._1,i._2.size))
    println("number=" + number)
    val sortNumber: List[(String,Int)] = number.toList.sortWith{
      (left,right) => {
        left._2 > right._2
      }
    }.take(3)
    println("sortNumber=" + sortNumber)

  }
}

  3)方式

  4)案例实操

package com.yuange.scala.day04

object TestWordCounThree {
  def main(args: Array[String]): Unit = {
    val tuples = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1))
    val testList: List[(String,Int)] = tuples.flatMap{
      t => {
        val str: Array[String] = t._1.split(" ")
        str.map(word => (word,t._2))
      }
    }

    val testMap: Map[String,List[(String,Int)]] = testList.groupBy(t=>t._1)
    val testMap2: Map[String,List[Int]] = testMap.mapValues{
      datas => datas.map(t => t._2)
    }
    val testMap3: Map[String,Int] = testMap2.map(t => (t._1,t._2.sum))
    println(testMap3)
  }
}

7.8 队列

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

  2案例实操

package com.yuange.scala.day04

import scala.collection.mutable

object TestQueue {
  def main(args: Array[String]): Unit = {
    val que = new mutable.Queue[String]()
    que.enqueue("zhangsan","lisi","wangwu")
    println(que.dequeue())
    println(que.dequeue())
    println(que.dequeue())
  }
}

7.9 并行集合

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

  2案例实操

package com.yuange.scala.day04

object TestPar {
  def main(args: Array[String]): Unit = {
    val result = (0 to 100).map{case_ => Thread.currentThread.getName}
    val result2 = (0 to 100).map{case_ => Thread.currentThread.getName}
    println(result)
    println(result2)
  }
}
原文地址:https://www.cnblogs.com/LzMingYueShanPao/p/14798102.html