Scala集合

Posted 岱宗夫如何、

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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).mapcase _ => 
Thread.currentThread.getName
 val result2 = (0 to 100).par.mapcase _ => 
Thread.currentThread.getName

来源:

尚硅谷

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

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

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

scala集合与数据结构

1、数据结构特点

Scala同时支持可变集合和不可变集合,不可变集合从不可变,可以安全的并发访问。

两个主要的包

不可变集合:scala.collection.immutable

可变集合: scala.collection.mutable

Scala优先采用不可变集合,对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本。

不可变集合继承层次:

   

技术图片

可变集合继承层次:

   

技术图片

   

2、数组

2.1、定义定长数组

我们可以定义一个固定长度大小和类型的定长数组

//定义一个数组长度为10,类型为Int的固定大小数组

val array = new Array[Int](10)

array(1) = 10

array(2) = 20

//访问数组当中的某一个下标元素值

println(array(1))

//直接使用apply方法进行生成一个数组

val array2 = Array(1,2,3)

//访问数组的元素

println(array2(2))

  

   

2.2、变长数组

我们也可以通过ArrayBuffer来定义一个变长数组

val array3 = new ArrayBuffer[Int]()

array3.append(20)

val array4 =  ArrayBuffer[String]()

array4.append("helloworld")

2.3、定长数组与变长数组的相互转换

    //定长数组转换成变长数组

    val toBuffer = array.toBuffer

    toBuffer.append(50)

    //变长数组准换成定长数组

val toArray = array3.toArray

   

2.4、多维数组

我们可以通过Array的ofDim方法来定义一个多维的数组,多少行,多少列,都是我们自己定义说了算

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

dim(1)(1) = 11.11

println(dim.mkString(","))

2.5、scala当中数组的遍历

val array5 = ArrayBuffer(1,2,3,4,5,6)

for(x <- array5){

println(x )

}

   

   

2.6、数组的常见算法

val array6 = Array(1,2,3,4,5,6)

//求和

array6.sum

//求最大值

array6.max

//排序

array6.sorted

3、元组tuple

在scala当中提供元组tuple的数据类型,可以理解tuple为一个容器,可以存放各种不同的数据类型的数据,例如一个Tuple当中既可以存放String类型数据,同时也可以存放Int类型的数据

注意:注意元组一旦创建之后,就是不可变的,也就是说元组当中没有添加和删除元素这一说

   

3.1、创建元组

创建元组,直接使用小括号,小括号当中存放我们元组当中各种类型的元素即可

val tuple1 = ("hello",1,5.0f)

println(tuple1)

   

3.2、元组数据的访问

访问元组当中的数据直接使用_加角标即可,但是要注意,元组当中的数据角标是从1开始的

val tuple1 = ("hello",1,5.0f)

println(tuple1)

   

val tuple1Result = tuple1._1

println(tuple1Result)

   

3.3、元组的遍历

val tuple1 = ("hello",1,5.0f)

println(tuple1)

   

val tuple1Result = tuple1._1

println(tuple1Result)

   

//第一种方式遍历元组

for(x <- tuple1.productIterator){

println(x)

}

//第二种方式遍历元组

tuple1.productIterator.foreach( x => println(x))

   

   

4、映射Map

scala当中的Map集合与java当中的Map类似,也是key,value对形式的

   

4.1、不可变映射

val map1 = Map("hello" ->"world","name" -> "zhangsan","age" -> 18)

   

4.2、可变映射及其操作

val map2 = scala.collection.mutable.Map("hello" ->"world","name" -> "zhangsan","age" -> 18)

//可变map添加元素

map2.+=("address" ->"地球")

println(map2)

//可变map删除元素.注意,删除元素是返回一个删除元素之后的map,原来的map并没有改变

val map3 = map2.-("address")

println(map2)

println(map3)

   

//可变map更新元素

map2("address") ="火星"

println(map2)

//或者使用覆盖key的方式来更细元素

map2 += ("address" -> "北京")

println(map2)

//或者使用 + 来进行更新元素

//注意,map当中没有phonNo这个key,则不能更细

map2 +("address" ->"上海","phonNo" -> "13688886666")

println(map2)

   

4.3、获取map当中指定的key值

//通过key来进行取值

map2.get("address")

//通过key来进行取值,如果没有这个key,就用后面给定的默认值

map2.getOrElse("address","非洲")

//通过key来进行取值,真的没有这个key,那么就用后面给定的默认值

map2.getOrElse("phoNo","13133335555")

   

   

4.4、遍历Map当中的元素

//遍历keyvalue

for((k,v) <- map2){

println(k)

println(v)

}

   

//遍历获取所有的key

for(k <- map2.keys) {

println(k)

}

//遍历获取所有的value

for(v <- map2.values) {

println(v)

}

   

//打印keyvalue

for(kv <- map2){

println(kv)

}

   

4.5、将对偶的数组转变为map

//将对偶的元组转变为map

val arrayMap = Array(("name","zhangsan"),("age",28))

val toMap = arrayMap.toMap

println(toMap)

   

5、列表(List)

scala当中也提供有与java类似的List集合操作

5.1、创建列表

注意:列表当中的元素类型可以是不同的,这一点与我们元组类似,但是列表当中的元素是可以删减的

val list1 = List("hello",20,5.0f)

println(list1)

   

5.2、访问列表当中的元素

//访问列表当中的元素

val list1Result = list1(0)

println(list1Result)

5.3、列表当中添加元素

我们可以从列表头部或者尾部添加元素

val list2 = list1:+50

val list3 = 100+:list1

println(list2)

println(list3)

   

5.4、List的创建与追加元素

Nil是一个空的List,定义为List[Nothing]

//尾部添加了Nil,那么就会出现List集合里面装List集合的现象

val list4 = 1::2 ::3 :: list1 ::Nil

println(list4)

//尾部没有添加Nil的值,那么所有的元素都压平到一个集合里面去了

val list5 = 1::2::3::list1

println(list5)

   

5.5、变长List的创建与使用

val list6 = new ListBuffer[String]

list6.append("hello")

list6.append("world")

println(list6.mkString(","))

val list7 = list6.toList

println(list7)

   

5.6、List操作延伸阅读

Scala是函数式风格与面向对象共存的编程语言,方法不应该有副作用是函数风格编程的一个重要的理念。方法唯一的效果应该是计算并返回值,用这种方式工作的好处就是方法之间很少纠缠在一起,因此就更加可靠和可重用。另一个好处(静态类型语言)是传入传出方法的所有东西都被类型检查器检查,因此逻辑错误会更有可能把自己表现为类型错误。把这个函数式编程的哲学应用到对象世界里以为着使对象不可变。

前面一章介绍的Array数组是一个所有对象都共享相同类型的可变序列。比方说Array[String]仅包含String。尽管实例化之后你无法改变Array的长度。因此,Array是可变的对象。

说到共享相同类型的不可变对象类型,Scala的List类才是。和数组一样,List[String]包含的仅仅是String。Scala的List不同于Java的java.util.List,总是不可变的(Java的List是可变)。更准确的说法,Scala的List是设计给函数式风格的编程用的。

   

(1)List类型定义以及List的特点:

//字符串类型List

scala> val fruit=List("Apple","Banana","Orange")

fruit: List[String] = List(Apple, Banana, Orange)

//前一个语句与下面语句等同

scala> val fruit=List.apply("Apple","Banana","Orange")

fruit: List[String] = List(Apple, Banana, Orange)

//数值类型List

scala> val nums=List(1,2,3,4,5)

nums: List[Int] = List(1, 2, 3, 4, 5)

//多重ListList的子元素为List

scala> val list = List(List(1, 2, 3), List("adfa", "asdfa", "asdf"))

list: List[List[Any]] = List(List(1, 2, 3), List(adfa, asdfa, asdf))

   

//遍历List

scala> for(i <- list; from=i; j<-from)println(j)

1

2

3

adfa

asdfa

asdf

(2)List与Array的区别:

1、List一旦创建,已有元素的值不能改变,可以使用添加元素或删除元素生成一个新的集合返回。

如前面的nums,改变其值的话,编译器就会报错。而Array就可以成功

scala>nums(3)=4

<console>:10: error: value update is not a member of List[Int]

nums(3)=4

^

2、List具有递归结构(Recursive Structure),例如链表结构

List类型和气他类型集合一样,它具有协变性(Covariant),即对于类型S和T,如果S是T的子类型,则List[S]也是List[T]的子类型。

例如:

scala>var listStr:List[Object] = List("This", "Is", "Covariant", "Example")

listStr:List[Object] = List(This, Is, Covariant, Example)

   

//空的List,其类行为Nothing,NothingScala的继承层次中的最底层

//,Nothing是任何Scala其它类型如String,Object等的子类

scala> var listStr = List()

listStr:List[Nothing] = List()

   

scala>var listStr:List[String] = List()

listStr:List[String] = List()

(3)List常用构造方法

//1、常用::Nil进行列表构建

scala> val nums = 1 :: (2:: (3:: (4 :: Nil)))

nums: List[Int] = List(1, 2, 3, 4)

//由于::操作符的优先级是从右向左的,因此上一条语句等同于下面这条语句

scala> val nums = 1::2::3::4::Nil

nums:List[Int] = List(1, 2, 3, 4)

至于::操作符的使用将在下面介绍

(4)List常用操作

//判断是否为空

scala> nums.isEmpty

res5: Boolean = false

//取第一个元素

scala> nums.head

res6: Int = 1

//取列表第二个元素

scala>nums.tail.head

res7: Int = 2

   

//取第三个元素

scala>nums.tail.tail.head

res8: Int = 3

   

//插入操作

//在第二个位置插入一个元素

scala>nums.head::(3::nums.tail)

res11: List[Int] = List(1, 3, 2, 3, 4)

   

scala> nums.head::(nums.tail.head::(4::nums.tail.tail))

res12: List[Int] = List(1, 2, 4, 3, 4)

   

//插入排序算法实现

def isort(xs: List[Int]):List[Int] = {

if(xs.isEmpty) Nil

else insert(xs.head, issort(xs.tail))

}

   

def insert(x:Int, xs:List[Int]):List[Int] = {

if(xs.isEmpty || x <= xs.head) x::xs

else xs.head :: insert(x, xs.tail)

}

   

//连接操作

scala>List(1, 2, 3):::List(4, 5, 6)

res13: List[Int] = List(1, 2, 3, 4, 5, 6)

   

//去除最后一个元素外的元素,返回的是列表

scala> nums.init

res13: List[Int] = List(1, 2, 3)

   

//取出列表最后一个元素

scala>nums.last

res14: Int = 4

   

//列表元素倒置

scala> nums.reverse

res15: List[Int] = List(4, 3, 2, 1)

//一些好玩的方法调用

scala> nums.reverse.reverse == nums

//丢弃前面n个元素

scala>nums drop 3

res16: List[Int] = List(4)

//获取前面n个元素

scala>nums take 1

res17: List[Int] = List[1]

//将列表进行分割

scala> nums.splitAt(2)

res18: (List[Int], List[Int]) = (List(1, 2),List(3, 4))

//前一个操作与下列语句等同

scala> (nums.take(2),nums.drop(2))

res19: (List[Int], List[Int]) = (List(1, 2),List(3, 4))

//Zip操作

scala> val nums=List(1,2,3,4)

nums: List[Int] = List(1, 2, 3, 4)

scala> val chars=List(‘1‘,‘2‘,‘3‘,‘4‘)

chars: List[Char] = List(1, 2, 3, 4)

//返回的是List类型的元组(Tuple),返回的元素个数与最小的List集合的元素个数一样

scala> nums zip chars

res20: List[(Int, Char)] = List((1,1), (2,2), (3,3), (4,4))

   

//List toString方法

scala> nums.toString

res21: String = List(1, 2, 3, 4)

   

//List mkString方法

scala> nums.mkString

res22: String = 1234

   

//转换成数组

scala> nums.toArray

res23: Array[Int] = Array(1, 2, 3, 4)

(5)List伴生对象方法

//apply方法

scala> List.apply(1, 2, 3)

res24: List[Int] = List(1, 2, 3)

//range方法,构建某一值范围内的List

scala> List.range(2, 6)

res25: List[Int] = List(2, 3, 4, 5)

//步长为2

scala> List.range(2, 6,2)

res26: List[Int] = List(2, 4)

//步长为-1

scala> List.range(2, 6,-1)

res27: List[Int] = List()

scala> List.range(6,2 ,-1)

res28: List[Int] = List(6, 5, 4, 3)

//构建相同元素的List

scala> List.make(5, "hey")

res29: List[String] = List(hey, hey, hey, hey, hey)

   

//unzip方法

scala> List.unzip(res20)

res30: (List[Int], List[Char]) = (List(1, 2, 3, 4),List(1, 2, 3, 4))

   

//list.flatten,将列表平滑成第一个无素

scala> val xss =List(List(‘a‘, ‘b‘), List(‘c‘), List(‘d‘, ‘e‘))

xss: List[List[Char]] = List(List(a, b), List(c), List(d, e))

scala> xss.flatten

res31: List[Char] = List(a, b, c, d, e)

   

//列表连接

scala> List.concat(List(‘a‘, ‘b‘), List(‘c‘))

res32: List[Char] = List(a, b, c)

(6)::和:::操作符介绍

List中常用‘::‘,发音为"cons"。Cons把一个新元素组合到已有元素的最前端,然后返回结果List。

scala> val twoThree = List(2, 3)

scala> val oneTwoThree = 1 :: twoThree

scala> oneTwoThree

oneTwoThree: List[Int] = List(1, 2, 3)

上面表达式"1::twoThree"中,::是右操作数,列表twoThree的方法。可能会有疑惑。表达式怎么是右边参数的方法,这是Scala语言的一个例外的情况:如果一个方法操作符标注,如a * b,那么方法被左操作数调用,就像a.* (b)--除非方法名以冒号结尾。这种情况下,方法被右操作数调用。

List有个方法叫":::",用于实现叠加两个列表。

scala> val one = List(‘A‘, ‘B‘)

val one = List(‘A‘, ‘B‘)

scala> val two = List(‘C‘, ‘D‘)

scala> one:::two

res1: List[Char] = List(A, B, C, D)

6、Set集合

集是不重复元素的结合。集不保留顺序,默认是以哈希集实现。

如果想要按照已排序的顺序来访问集中的元素,可以使用SortedSet(已排序数据集),已排序的数据集是用红黑树实现的。

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

6.1、不可变集合的创建

val set1 =Set("1","1","2","3")

println(set1.mkString(","))

   

6.2、可变集合的创建以及添加元素

如果我们引入的集合的包是可变的,那么我们创建的集合就是可变的

import scala.collection.mutable.Set

val set2 = Set(1, 2, 3)

set2.add(4)

set2 += 5

//使用.这个方法添加元素,会返回一个新的集合

val set3 = set2.+(6)

println(set2.mkString(","))

println(set3.mkString("01"))

   

   

6.3、可变集合删除元素

set3 -= 1

println(set3.mkString("."))

   

set3.remove(2)

println(set3.mkString("."))

   

6.4、遍历Set集合元素

for(x <- set3){

println(x )

}

   

注意:如果要创建有序的set,那么需要使用SortedSet。用法与Set类似

更多Set集合操作参见如下:

http://www.runoob.com/scala/scala-sets.html

   

6.5、Set更多常用操作介绍

   

序号

方法

描述

1

def +(elem: A): Set[A]

为集合添加新元素,并创建一个新的集合,除非元素已存在

2

def -(elem: A): Set[A]

移除集合中的元素,并创建一个新的集合

3

def contains(elem: A): Boolean

如果元素在集合中存在,返回 true,否则返回 false。

4

def &(that: Set[A]): Set[A]

返回两个集合的交集

5

def &~(that: Set[A]): Set[A]

返回两个集合的差集

6

def ++(elems: A): Set[A]

合并两个集合

7

def drop(n: Int): Set[A]]

返回丢弃前n个元素新集合

8

def dropRight(n: Int): Set[A]

返回丢弃最后n个元素新集合

9

def dropWhile(p: (A) => Boolean): Set[A]

从左向右丢弃元素,直到条件p不成立

10

def max: A

查找最大元素

11

def min: A

查找最小元素

12

def take(n: Int): Set[A]

返回前 n 个元素

   

7、集合元素与函数的映射

我们可以使用map方法,传入一个函数,然后将这个函数作用在集合当中的每一个元素上面

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

   

val listFunc = List("name","age","zhangsan","lisi")

println(listFunc.map(x => x +"hello"))

println(listFunc.map(_.toUpperCase()))

   

flatmap:flat即压扁,压平,扁平化,效果就是将集合中的每个元素的子元素映射到某个函数并返回新的集合

   

val listFunc2 = List("address","phonNo")

println(listFunc2.flatMap( x => x +"WORLD"))

   

   

8、队列Queue

队列Queue是一个先进先出的结构

8.1、创建队列

//创建可变的队列

val queue1 = new mutable.Queue[Int]()

println(queue1)

   

8.2、队列当中添加元素

//队列当中添加元素

queue1 += 1

//队列当中添加List

queue1 ++=List(2,3,4)

println(queue1)

   

8.3、按照进入队列顺序,删除队列当中的元素(弹出队列)

val dequeue = queue1.dequeue()

println(dequeue)

println(queue1)

   

8.4、向队列当中加入元素(入队列操作)

//塞入元素到队列

queue1.enqueue(5,6,7)

println(queue1)

8.5、获取第一个与最后一个元素

//获取第一个元素

println(queue1.head)

//获取最后一个元素

println(queue1.last)

   

   

9、集合当中的化简、折叠与扫描操作

9.1、折叠、化简 reduce操作

将二元函数引用集合当中的函数

val reduceList = List(1,2,3,4,5)

//1-2-3-4-5 = -13

val reduceLeftList = reduceList.reduceLeft(_ - _)

val reduceLeftList2 = reduceList.reduceLeft((x,y) => x-y)

println(reduceLeftList)

println(reduceLeftList2)

//reduceRight操作

// 4-5 = -1

// 3- (-1) = 4

//2-4 = -2

//1 -(-2) = 3

val reduceRightList = reduceList.reduceRight(_ - _)

println(reduceRightList)

   

9.2、折叠、化简folder操作

fold函数将上一步返回的值作为函数的第一个参数继续传递参与运算,直到list中的所有元素被遍历。可以把reduceLeft看做简化版的foldLeft。相关函数:fold,foldLeft,foldRight,可以参考reduce的相关方法理解。

reduce的本质其实就是fold操作,只不过我们使用fold操作的时候,需要指定初始值fold操作

val foldList = List(1,9,2,8)

val foldResult = foldList.fold(10)((x,y) => x+y)

println(foldResult)

   

foldLeft操作

   

//50-1-9-2-8 = 30

val foldLeftResult = foldList.foldLeft(50)((x,y) => x-y)

println(foldLeftResult)

   

   

10、拉链操作

对于多个List集合,我们可以使用Zip操作,将多个集合当中的值绑定到一起去

val zipList1 = List("name","age","sex")

val zipList2 = List("zhangsan",28)

val zip = zipList1.zip(zipList2)

val toMap1 = zip.toMap

println(zip)

println(toMap1)

   

11、迭代器

对于集合当中的元素,我们也可以使用迭代器来进行遍历

val listIterator = List(1,2,"zhangsan")

val iterator = listIterator.iterator

while(iterator.hasNext){

println(iterator.next())

}

12、线程安全的集合

scala当中为了解决多线程并发的问题,提供对应的线程安全的集合

https://www.scala-lang.org/api/2.11.8/#package

SynchronizedBuffer

SynchronizedMap

SynchronizedPriorityQueue

SynchronizedQueue

SynchronizedSet

   

13、操作符

大致了解即可

  1. 如果想在变量名、类名等定义中使用语法关键字(保留字),可以配合反引号反引号:

    var `var` num:Int = 2

2) 这种形式叫中置操作符,A操作符B等同于A.操作符(B)

3) 后置操作符,A操作符等同于A.操作符,如果操作符定义的时候不带()则调用时不能加括号

4) 前置操作符,+、-、!、~等操作符A等同于A.unary_操作符。

5) 赋值操作符,A操作符=B等同于A=A操作符B

以上是关于Scala集合的主要内容,如果未能解决你的问题,请参考以下文章

Scala大数据深度好课Scala大数据操作实战

2021年大数据常用语言Scala(十九):基础语法学习 iterator迭代器

大数据技术之_16_Scala学习_08_数据结构(下)-集合操作+模式匹配

2021年大数据常用语言Scala(二十一):函数式编程 遍历 foreach

2021年大数据常用语言Scala:基础语法学习 循环

2021年大数据常用语言Scala(三十六):scala高级用法 泛型