【Scala】集合

目录

类型

不可变集合

可变集合

数组

不可变

可变数组

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

多维数组

List

list运算符

可变 ListBuffer

Set 集合

不可变 Set

可变 mutable.Set

Map 集合

可变 Map

元组

操作

通用操作

衍生集合操作

计算函数

排序

sorted

sortBy

sortWith

计算高级函数

实例

WordCount 案例

复杂案例

队列

并行集合

来源:


类型

序列 Seq 、集 Set 、映射 Map
都扩展自 Iterable 特质
都分为 可变 不可变 的版本
不可变集合:scala.collection.immutable
可变集合: scala.collection.mutable

不可变集合

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

可变集合

集合可以直接对原对象进行修改,而不会返回新的对象。类似 于 java StringBuilder 对象
建议:在操作集合的时候,不可变用符号,可变用方法

IndexedSeq LinearSeq 的区别:

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

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

数组

不可变

val arr =new Array[类型](大小)
    val arr01 = new Array[Int](4)
    println(arr01.length) // 4
    //(2)数组赋值
    //(2.1)修改某个元素的值
    arr01(3) = 10
    //(2.2)采用方法的形式给数组赋值
    arr01.update(0, 1)  //将第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 //末尾追加
    val ints1: Array[Int] = arr01 +: 5 //头部追加
    println(ints)
//如果使用空格 替换掉 “.” 的时候,如果后面的操作符是以":" 号结尾的,那操作符是从右边往左边的
    val new = Arr :+ 15
    val new1 = 15 +: Arr
    //         19 +: 32 +: Arr

第二种方式定义数组

val arr1 = Array (1, 2)

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

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

可变数组

import scala.collection.mutable.ArrayBuffer
val arr01 = ArrayBuffer[Any](3, 2, 5)
    //(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)
    arr01.foreach(print(_ ))
    println()

    //(3.2)向数组最后追加数据
    arr01.append(5,6)//追加 5,6
    arr01.foreach(print(_)) 


    //(3.3)向指定的位置插入数据
    arr01.insert(0,7,8) //第0个位置 插入 7,8 
    arr01.foreach(print(_))
    println()
    println("arr01.hash=" + arr01.hashCode())
    //(4)修改元素
    arr01(1) = 9 //修改第 2 个元素的值
    println("--------------------------")
    for (i <- arr01) {
      println(i)
    }
    println(arr01.length) // 5
1 ArrayBuffer 是有序的集合
2 )增加元素使用的是 append 方法 () ,支持可变参数

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

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

多维数组

val arr = Array.ofDim[Double](3,4)
说明:二维数组中有三个一维数组,每个一维数组中有四个元素
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()
 }
 }
}

List

1 List 默认为不可变集合
2 )创建一个 List (数据有顺序,可重复)
3 )遍历 List
4 List 增加数据
5 )集合间合并:将一个整体拆成一个一个的个体,称为扁平化
6 )取指定数据
7 )空集合 Nil
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))
 //(3)遍历 List
 //list.foreach(println)
 //list1.foreach(println)
 //list3.foreach(println)
 //list4.foreach(println)
 list5.foreach(println)
 }
}

list运算符

package test
/**
  * scala中的:: , +:, :+, :::, +++, 等操作;
  */
object listTest {
  def main(args: Array[String]): Unit = {
    val list = List(1,2,3)
    // :: 用于的是向队列的头部追加数据,产生新的列表, x::list,x就会添加到list的头部
    println(4 :: list)  //输出: List(4, 1, 2, 3)
    // .:: 这个是list的一个方法;作用和上面的一样,把元素添加到头部位置; list.::(x);
    println( list.:: (5)) //输出: List(5, 1, 2, 3)
    // :+ 用于在list尾部追加元素; list :+ x;
    println(list :+ 6)  //输出: List(1, 2, 3, 6)
    // +: 用于在list的头部添加元素;
    val list2 = "A"+:"B"+:Nil //Nil Nil是一个空的List,定义为List[Nothing]
    println(list2)  //输出: List(A, B)
    // ::: 用于连接两个List类型的集合 list ::: list2
    println(list ::: list2) //输出: List(1, 2, 3, A, B)
    // ++ 用于连接两个集合,list ++ list2
    println(list ++ list2) //输出: List(1, 2, 3, A, B)
  }
}

可变 ListBuffer

1 )创建一个可变集合 ListBuffer
2 )向集合中添加数据
3 )打印集合数据
import scala.collection.mutable.ListBuffer
object TestList {
 def main(args: Array[String]): Unit = {
 //(1)创建一个可变集合
 val buffer = ListBuffer(1,2,3,4)
 //(2)向集合中添加数据
 buffer.+=(5)
buffer.append(6)
buffer.insert(1,2)
 //(3)打印集合数据
 buffer.foreach(println)
//(4)修改数据
buffer(1) = 6
buffer.update(1,7)
//(5)删除数据
buffer.-(5)
buffer.-=(5)
buffer.remove(5)
 }
}

Set 集合

不可变 Set

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)
 }
 }
}

可变 mutable.Set

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
映射
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)})
 }
}

可变 Map

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)
map("d") = 5
 //(2)打印集合
 map.foreach((kv)=>{println(kv)})
 }
}

元组

元组可理解为一个容器,存放各种相同或不同类型的数据。
将多个无关的数据封装为一个整体,称为 元组。
注意:元组中最大只能有 22 个元素。
object TestTuple {
 def main(args: Array[String]): Unit = {
 //(1)声明元组的方式:(元素 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)
 val map1 = Map(("a",1), ("b",2), ("c",3))
 map.foreach(tuple=>{println(tuple._1 + "=" + tuple._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)
 //(2)获取集合大小,等同于 length
 println(list.size)
 //(3)循环遍历
 list.foreach(println)
 //(4)迭代器
 for (elem <- list.itera tor) {
     println(elem)
 }

 while (iter.hasNext){
      println(iter.next())
    }

 //(5)生成字符串
 println(list.mkString(","))
 //(6)是否包含
 println(list.contains(3))        //如果存在返回true,不存在返回false
 }
}

衍生集合操作

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)获取集合的头
//获取集合的头使用head方法,可迭代的类型都可以用,一般在有序的类型里面有,无序的不考虑头和尾
 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)
 //(6)取前(后)n 个元素
 println(list1.take(3))
 println(list1.takeRight(3))
 //(7)去掉前(后)n 个元素
 println(list1.drop(3))
 println(list1.dropRight(3))


//两个集合的操作 

 //(8)并集
 println(list1.union(list2))
 println(list1 ::: list2)


/如果是set做并集。那么重复的数据会被去重
    val set = Set(6,12,33,45,56)
    val set2 = Set(32,65,45,46,321,6)
    val union2 = set.union(set2)
    println(union2)
    println(set ++ set2)

 //(9)交集
 println(list1.intersect(list2))
 //(10)差集
 println(list1.diff(list2))
 //(11)拉链 注:如果两个集合的元素个数不相等,那么会将同等数量的数据进行拉链,多余的数据省略不用
 println(list1.zip(list2))
//    (12) 滑窗
    //滑窗的意思是,第一次取123元素,第二次去234,每次取三个这样滑下去,每次取多少可以定义
    println(list.sliding(3)) //滑窗使用sliding方法,里面的参数是每次滑的元素是几个,可以看到是一个迭代器
    for(i <- list.sliding(3)){ //使用类似于迭代器的方式遍历出来
      println(i)
    }
println("================")
    //要是里面有两个参数的话,第二个参数是步长,一个参数的时候默认步长是1
    for(i <- list.sliding(3,2)){
      println(i)
    }
 }
}

计算函数

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)
 }
}

排序

sorted

对一个集合进行自然排序,通过传递隐式的 Ordering
println(list.sorted) //这是升序,从小到大
println(list.sorted.reverse) //降序可以先排序然后翻转列表,可以达到效果
println(list.sorted(Ordered[Int])) //降序

sortBy

对一个属性或多个属性进行排序,通过它的类型。
println(list.sortBy(x => x)) //按照元素大小排序
println(list.sortBy(x => x.abs))  //按照元素的绝对值大小排序

sortWith

基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑。
println(list.sortWith((x, y) => x < y)) //按元素大小升序排序
println(list.sortWith((x, y) => x > y)) //按元素大小降序排序

计算高级函数

(1) 过滤
遍历一个集合并从中获取满足指定条件的元素组成一个新的集合
(2) 转换/映射(map)
将集合中的每一个元素映射到某一个函数
(3) 扁平化 (flatten)
有点像两个列表要合并,列表里面还套着列表,我们要将他打散,这样的操作就叫做扁平化
(4) 扁平化+映射 注:flatMap相当于先进行map操作,再进行flatten操作集合中的每个元素的子元素映射到某个函数并返回新的集合

就是将多个集合展开,组合成新的一个集合。
(5) 分组(group)
按照指定的规则对集合的元素进行分组,分组是转换成了map
(6) 简化(reduce归约)

通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最

终获取结果。
(7) 折叠(fold)
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))
 }
}
//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 )
 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)
 }
}
//Fold
list(1,2,3,4)
//10+1+2+3+4
println(list.fold(10)(_+_))
//10-1-2-3-4
list.foldLeft(10)(_-_)
//1-(2-(3-(4-10)))
list.foldRight(10)(_-_)

实例

map1++map2 如果有相同的key,map1的value会被map2的value覆盖

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)
//fold 要求两个()()里 的变量相同
 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)
 }
}

WordCount 案例

单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果
package com.qihang.bigdata.spark.core

class Person(){}


object Test {
  def main(args: Array[String]): Unit = {
    //数据
    val stringList:List[String]=List(
      "hello",
      "hello world",
      "hello scala",
      "hello spark from scala",
      "hello flink from scala"
    )
    //对字符串切分,打散所有单词的列表
//    val wordList1 = stringList.map(_.split(" "))
//    val wordList2 = wordList1.flatten
    val wordList = stringList.flatMap(_.split(" "))
    println(wordList) //List(hello, hello, world, hello, scala, hello, spark, from, scala, hello, flink, from, scala)
    val groupMap = wordList.groupBy(word => word)
    println(groupMap) //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))
    //对分组之后的list去长度,当成value
    val countMap : Map[String,Int]= groupMap.map(kv => (kv._1, kv._2.length))
    //排序,需要转化为list,进行排序,取前三
    val sortList:List[(String,Int)]=countMap.toList
      .sortWith( _._2 > _._2)
      .take(3)
    println(sortList) 

  }
}

复杂案例

package com.qihang.bigdata.spark.core

class Person(){}


object Test {
  def main(args: Array[String]): Unit = {
    //数据
    val stringList:List[(String,Int)]=List(
      ("hello",1),
      ("hello world",2),
      ("hello scala",3),
      ("hello spark from scala",1),
      ("hello flink from scala",2)
    )
    //思路1:打散,变成上一个案例
    val newStringList:List[String]=stringList.map(
      kv=>{
        (kv._1.trim + " ")*kv._2
      }
    )
    val wordCountList:List[(String,Int)]=newStringList
      .flatMap(_.split(" "))
      .groupBy(word=>word)
      .map(kv=>(kv._1,kv._2.length))
      .toList
      .sortBy(_._2)(Ordering[Int].reverse) //降序排序
      .take(3)
    //2 基于预处理直接进行处理
    //将字符串打散,并和个数包装成二元组
    val preCountList:List[(String,Int)] = stringList.flatMap(
      tuple =>{
          val strings:Array[String]=tuple._1.split(" ")
          strings.map( word => (word, tuple._2) )
      }
    )
    println(preCountList)
    //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))

    //对二元组进行分组
    val perCountMap:Map[String,List[(String,Int)]] = preCountList.groupBy( _._1 )
    println(perCountMap)
    //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)))

    //叠加每个单词预统计的个数值
    //mapValues 将原有的元素集转换成新的元素集
    val countMap = perCountMap.mapValues(
      tupleList => tupleList.map(_._2).sum
    )
    println(countMap)
    //Map(world -> 2, flink -> 2, spark -> 1, scala -> 6, from -> 3, hello -> 9)

    //转List 排序取前三
    val countList = countMap.toList //List((world,2), (flink,2), (spark,1), (scala,6), (from,3), (hello,9))
      .sortWith( _._2 > _._2 )
      .take(3)
    println(countList)
  }
}

队列

进队和出队的方法分别为 enqueue dequeue
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())
 }
}

并行集合

在集合和函数之间.par
val result1 = (0 to 100).map{case _ => 
Thread.currentThread.getName}
 val result2 = (0 to 100).par.map{case _ => 
Thread.currentThread.getName}

来源:

尚硅谷

(8条消息) scala中的:: , +:, :+, :::, +++, 等操作的含义_scala:::_JasonLee实时计算的博客-CSDN博客

 (11条消息) Scala 集合常用函数_scala滑窗_气质&末雨的博客-CSDN博客

每天学一点Scala之 高阶函数 flatten_51CTO博客_scala高阶函数

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

返返返

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值