scala(十三) 集合

2022-04-18 15:12:01 浏览数 (1)

集合简介

说明:

  1. Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质。
  2. 对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本,分别位于以下两个包 不可变集合:scala.collection.immutable 可变集合: scala.collection.mutable

不可变集合继承图

不可变集合继承图不可变集合继承图
  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的区别: 1.IndexSeq是通过索引来查找和定位,因此速度快,比如String就是一个索引集合,通过索引即可定位 2.LineaSeq是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找

可变集合继承图

可变集合继承图可变集合继承图

集合操作的通用方法:

  1. 带 与带-的区别: 带 是添加元素 带-是删除元素
  2. 一个 /-与两个 /-的区别 一个 /-是添加/删除单个元素 两个 /-是添加/删除一个集合所有元素
  3. 冒号在前、冒号在后、不带冒号的区别 冒号在前是将元素添加到集合末尾 冒号在后是将元素添加到集合最前面 不带冒号是将元素添加到集合末尾
  4. 带=与不带=的区别 带=是修改集合本身 不带=是生成一个新集合,原集合没有改变
  5. update与updated的区别: update是修改集合本身 updated是生成一个新集合,原集合没有改变

集合常用的方法

List 作为参考

代码语言:javascript复制
scala> list.
                flatMap              min                 sortBy
  :             flatten              minBy               sortWith
 :              fold                 mkString            sorted
/:              foldLeft             nonEmpty            span
:               foldRight            orElse              splitAt
::              forall               padTo               startsWith
:::             foreach              par                 stringPrefix
:              genericBuilder       partition           sum
WithFilter      groupBy              patch               tail
addString       grouped              permutations        tails
aggregate       hasDefiniteSize      prefixLength        take
andThen         hashCode             product             takeRight
apply           head                 productArity        takeWhile
applyOrElse     headOption           productElement      to
canEqual        indexOf              productIterator     toArray
collect         indexOfSlice         productPrefix       toBuffer
collectFirst    indexWhere           reduce              toIndexedSeq
combinations    indices              reduceLeft          toIterable
companion       init                 reduceLeftOption    toIterator
compose         inits                reduceOption        toList
contains        intersect            reduceRight         toMap
containsSlice   isDefinedAt          reduceRightOption   toSeq
copyToArray     isEmpty              repr                toSet
copyToBuffer    isTraversableAgain   reverse             toStream
corresponds     iterator             reverseIterator     toString
count           last                 reverseMap          toTraversable
diff            lastIndexOf          reverse_:::         toVector
distinct        lastIndexOfSlice     runWith             transpose
drop            lastIndexWhere       sameElements        union
dropRight       lastOption           scan                unzip
dropWhile       length               scanLeft            unzip3
endsWith        lengthCompare        scanRight           updated
equals          lift                 segmentLength       view
exists          map                  seq                 withFilter
filter          mapConserve          size                zip
filterNot       max                  slice               zipAll
find            maxBy                sliding             zipWithIndex
  1. 获取集合长度
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8,9,10)

length

代码语言:javascript复制
println(s"length=${list.length}")
length=10

size

代码语言:javascript复制
println(s"size=${list.size}")
size=10
  1. 判断集合是否为空(isEmpty)
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8,9,10)
val list2=List()
代码语言:javascript复制
println(list.isEmpty) // false
代码语言:javascript复制
println(list2.isEmpty) // true
  1. 判断是否包含某个元素(contains)
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8,9,10)
代码语言:javascript复制
println(list.contains(5)) // true
代码语言:javascript复制
println(list.contains(100)) // false
  1. 获取集合元素组成的字符串(mkString)
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8,9,10)

mkString(分隔符)

代码语言:javascript复制
println(list.mkString(","))
1,2,3,4,5,6,7,8,9,10
  1. 元素遍历
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8,9,10)
for(e <- list){
  println(s"e=$e")
}
代码语言:javascript复制
e=1
e=2
e=3
e=4
e=5
e=6
e=7
e=8
e=9
e=10
  1. 迭代器
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8,9,10)
// 获得一个迭代器
val iterator: Iterator[Int] = list.iterator
// 判断是否有下一个元素
while(iterator.hasNext){
  // 取值
  println(s"next=${iterator.next()}")
}
代码语言:javascript复制
next=1
next=2
next=3
next=4
next=5
next=6
next=7
next=8
next=9
next=10

除了使用while 也可以使用for

代码语言:javascript复制
val iterator: Iterator[Int] = list.iterator

for (it<-iterator){
  println(it)
}

衍生集合

  1. 去重(distinct)
代码语言:javascript复制
val list=List(1,2,3,44,3,5,3,1,2)
//去重
val newList: List[Int] = list.distinct
代码语言:javascript复制
println(newList)
List(1, 2, 3, 44, 5)
  1. 获取除开前N个元素的所有元素(drop)
代码语言:javascript复制
val list=List(1,2,3,44,3,5,3,1,2)
// 弹出前三个元素
val newList: List[Int] = list.drop(3)
代码语言:javascript复制
println(newList)
List(44, 3, 5, 3, 1, 2)
  1. 获取除开后N个元素的所有元素(dropRight)
代码语言:javascript复制
val list=List(1,2,3,44,3,5,3,1,2)
val newList: List[Int] = list.dropRight(3)
代码语言:javascript复制
println(newList)
List(1, 2, 3, 44, 3, 5)
  1. 获取第一个元素(head)
代码语言:javascript复制
val list=List(1,2,3,44,3,5,3,1,2)
val value: Int = list.head
代码语言:javascript复制
println(value) //1
  1. 获取最后一个元素
代码语言:javascript复制
val list=List(1,2,3,44,3,5,3,1,2)
val value: Int = list.last
代码语言:javascript复制
println(value) // 2
  1. /获取除开最后一个元素的其他所有元素(init)
代码语言:javascript复制
val list=List(1,2,3,44,3,5,3,1,2)
val newList: List[Int] = list.init
代码语言:javascript复制
println(newList)
List(1, 2, 3, 44, 3, 5, 3, 1)
  1. 获取除开第一个元素的其他所有元素(tail)
代码语言:javascript复制
val list=List(1,2,3,44,3,5,3,1,2)
val newList: List[Int] = list.tail
代码语言:javascript复制
println(newList)
List(2, 3, 44, 3, 5, 3, 1, 2)
  1. 反转(reverse)
代码语言:javascript复制
val list=List(1,2,3,44,3,5,3,1,2)
println(list.reverse)
代码语言:javascript复制
List(2, 1, 3, 5, 3, 44, 3, 2, 1)
  1. 获取指定角标范围的子集合 [包前不包后](slice)
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8)
val newList: List[Int] = list.slice(2, 5)
代码语言:javascript复制
println(newList)
List(3, 4, 5)
  1. 滑窗(sliding) size: 窗口的长度 step: 滑动的长度
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8)

//滑窗
val iterator: Iterator[List[Int]] = list.sliding(2)

for (it <-iterator){
  println(it)
}
代码语言:javascript复制
List(1, 2)
List(2, 3)
List(3, 4)
List(4, 5)
List(5, 6)
List(6, 7)
List(7, 8)

若不指定 step 默认长度为1,当然我们可以自定义step

代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8)

//滑窗
val iterator: Iterator[List[Int]] = list.sliding(3,2)

for (it <-iterator){
  println(it)
}
代码语言:javascript复制
List(1, 2, 3)
List(3, 4, 5)
List(5, 6, 7)
List(7, 8)

注意 step 超过 size 会造成数据丢失

代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8)

//滑窗
val iterator: Iterator[List[Int]] = list.sliding(2,3)

for (it <-iterator){
  println(it)
}
代码语言:javascript复制
List(1, 2)
List(4, 5)
List(7, 8)
  1. 获取前N个元素(take)
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8)
val newList: List[Int] = list.take(3)
代码语言:javascript复制
println(newList)
List(1, 2, 3)
  1. 获取后N个元素(takeRight)
代码语言:javascript复制
val list=List(1,2,3,4,5,6,7,8)
val newList: List[Int] = list.takeRight(3)
代码语言:javascript复制
println(newList)
List(6, 7, 8)
  1. 交集 [取两个集合共同的元素]('intersect')
代码语言:javascript复制
val list1=List(1,2,3,4,5,6,7,8)
val list2=List(5,6,7,8,9,10)

val newList: List[Int] = list1.intersect(list2)
代码语言:javascript复制
println(newList)
List(5, 6, 7, 8)
  1. 差集 [A差B的结果就是取A中有B中没有的元素](diff)
代码语言:javascript复制
val list1=List(1,2,3,4,5,6,7,8)
val list2=List(5,6,7,8,9,10)

val newList: List[Int] = list1.diff(list2)
代码语言:javascript复制
println(newList)
List(1, 2, 3, 4)
  1. 并集(union)
代码语言:javascript复制
val list1=List(1,2,3,4,5,6,7,8)
val list2=List(5,6,7,8,9,10)

val newList: List[Int] = list1.union(list2)
代码语言:javascript复制
println(newList)
List(1, 2, 3, 4, 5, 6, 7, 8, 5, 6, 7, 8, 9, 10)
  1. 拉链(zip),两个集合之间元素交叉
代码语言:javascript复制
val list1=List("张三","李四","王五")
val list2=List("阿娇","糖心","绣花")

val newList: List[(String, String)] = list1.zip(list2)
代码语言:javascript复制
println(newList)
List((张三,阿娇), (李四,糖心), (王五,绣花))

有一天王五分手了,没有了女朋友,张三和李四就不叫王五玩了。

代码语言:javascript复制
val list1=List("张三","李四","王五")
val list2=List("阿娇","糖心")

val newList: List[(String, String)] = list1.zip(list2)

使用拉链,必须保证元素之间能够交叉。

代码语言:javascript复制
println(newList)
List((张三,阿娇), (李四,糖心))
  1. 反拉链(unzip)
代码语言:javascript复制
val list1=List("张三","李四","王五")
val list2=List("阿娇","糖心")

val newList: List[(String, String)] = list1.zip(list2)
代码语言:javascript复制
println("反拉链:" newList.unzip)
println("拉链:" newList)
代码语言:javascript复制
反拉链:(List(张三, 李四),List(阿娇, 糖心))
拉链:List((张三,阿娇), (李四,糖心))
  1. 将元素与角标拉链(zipWithIndex),将返回一个角标。
代码语言:javascript复制
println("反拉链:" newList.unzip)
println("角标拉链:" newList.zipWithIndex)
println("拉链:" newList)
代码语言:javascript复制
反拉链:(List(张三, 李四),List(阿娇, 糖心))
角标拉链:List(((张三,阿娇),0), ((李四,糖心),1))
拉链:List((张三,阿娇), (李四,糖心))

集合初级计算函数

  1. 获取最大值(max)
代码语言:javascript复制
val list=List[Int](23,1,2,34,5432,22)
代码语言:javascript复制
println(list.max) // 5432
  1. 获取最小值(min)
代码语言:javascript复制
val list=List[Int](23,1,2,34,5432,22)
代码语言:javascript复制
println(list.min) // 1
  1. 根据指定字段获取最大值(maxBy) maxBy(func: 集合元素类型 => B) maxBy里面的函数是针对集合每个元素进行操作 maxBy是根据函数的返回值获取最大元素
代码语言:javascript复制
val list2=List[(String,Int)](
      ("张三",19),
      ("春娇",18),
      ("牛二娃",8),
      ("刘大叔",39),
      ("李二婶",42),
      ("李四",19),
)
代码语言:javascript复制
println(list2.maxBy(_._2)) 
(李二婶,42)
  1. 根据指定字段获取最小值 minBy(func: 集合元素类型 => B ) minBy里面的函数是针对集合每个元素进行操作 minBy后续就是根据函数的返回值获取最小值
代码语言:javascript复制
val list2=List[(String,Int)](
      ("张三",19),
      ("春娇",18),
      ("牛二娃",8),
      ("刘大叔",39),
      ("李二婶",42),
      ("李四",19),
)
代码语言:javascript复制
println(list2.minBy(_._2)) 
(牛二娃,8)
  1. 求和
代码语言:javascript复制
 val list=List[Int](23,1,2,34,5432,22)
代码语言:javascript复制
println(list.sum) // 5514
  1. 排序

sorted sortBy(func: 集合元素类型 => B) sortBy里面的函数也是针对集合每个元素进行操作 sortBy后续是根据函数返回值进行排序

直接根据元素本身排序[默认升序]

代码语言:javascript复制
val list=List[Int](23,1,2,34,5432,22)
代码语言:javascript复制
println(list.sorted)
List(1, 2, 22, 23, 34, 5432)

根据指定字段排序【默认升序】

代码语言:javascript复制
val list=List[Int](23,1,2,34,5432,22)

自定义 Ordering 特质

代码语言:javascript复制
val ordered=new Ordering[Int]{
    override def compare(x: Int, y: Int) = {
        if(x<y) 1
        else if(x==y) 0
        else -1
    }
}
代码语言:javascript复制
println(list.sorted(ordered))
List(5432, 34, 23, 22, 2, 1)

sortWith[重点] sortWith(func: (集合元素类型,集合元素类型) => Boolean ) sortWith 中的函数如果第一个参数>第二个参数,降序 sortWith 中的函数如果第一个参数<第二个参数,升序

根据指定规则排序【指定升序或者降序】

代码语言:javascript复制
val list2=List[(String,Int)](
      ("张三",19),
      ("春娇",18),
      ("牛二娃",8),
      ("刘大叔",39),
      ("李二婶",42),
      ("李四",19),
    )

按年龄降序

代码语言:javascript复制
println(list2.sortWith(_._2 > _._2))
List((李二婶,42), (刘大叔,39), (张三,19), (李四,19), (春娇,18), (牛二娃,8))

按年龄升序

代码语言:javascript复制
println(list2.sortWith(_._2 < _._2))
List((牛二娃,8), (春娇,18), (张三,19), (李四,19), (刘大叔,39), (李二婶,42))

高阶函数

map map(func: 集合元素类型 => B ): 映射 map里面的函数是针对集合每个元素进行计算,计算完成之后会返回一个结果 map使用场景: 一般用于一对一,主要用于数据的类型/值的转换

案例:统计集合中字符串的个数并返回

代码语言:javascript复制
val list=List("java","python","scala","hadoop","hive")
代码语言:javascript复制
 //映射
val mapList: List[String] = list.map(s=>s"$s:${s.length}")
代码语言:javascript复制
println(mapList.mkString(","))
java:4,python:6,scala:5,hadoop:6,hive:4

flatten flatten只能压平第二层集合 flatten的应用场景: 一对多,只能用于集合嵌套集合的数据类型

代码语言:javascript复制
val list2=List[List[String]](
      List[String]("java","String","main"),
      List[String]("hadoop","hdfs","yarn"),
      List[String]("hive","python"),
)
代码语言:javascript复制
println(s"不使用平铺化= ${list2.mkString(",")}")
不使用平铺化= List(java, String, main),List(hadoop, hdfs, yarn),List(hive, python)
代码语言:javascript复制
val flattenList= list2.flatten
println(s"使用平铺化= ${flattenList.mkString(",")}")
使用平铺化= java,String,main,hadoop,hdfs,yarn,hive,python

flatMap 先进行map后进行 flatten flatMap(func: 集合元素类型 => 集合) flatMap里面的函数也是针对集合每个元素操作 flatMap的使用场景: 一对多 flatMap与flatten的区别: flatMap是先对数据转换再压平, flatten只是单纯的压平

案例:将句子转成单词

代码语言:javascript复制
val list3=List("hello spark hello java","hello hadoop spark","spark hadoop java")
代码语言:javascript复制
val newList: List[String] = list3.flatMap(work => {
      // 按照空格切分
      work.split(" ")
    })
代码语言:javascript复制
println(newList.mkString(","))
hello,spark,hello,java,hello,hadoop,spark,spark,hadoop,java

foreach foreach(func: 集合元素类型 => B):Unit foreach与map类似,唯一的区别在与map计算之后会生成一个新集合,foreach没有返回值 foreach相当于普通for循环, map相当于有yield表达式的for循环

集合遍历

代码语言:javascript复制
val list=List("java","python","scala","hadoop","hive")

打印输出

代码语言:javascript复制
list.foreach(s=>println(s))
代码语言:javascript复制
java
python
scala
hadoop
hive

filter filter( func: 集合元素类型 => Boolean ): 根据指定的规则过滤 filter里面的函数也是针对集合每个元素进行操作 filter保留的是函数返回值为true的数据

案例:剔除集合中java 字符串

代码语言:javascript复制
val list4=List("hello","spark","hello","java","hello","hadoop","spark","spark","hadoop","java")
代码语言:javascript复制
val newList4: List[String] = list4.filter(s => s.ne("java"))
代码语言:javascript复制
println(newList4 )
List(hello, spark, hello, hello, hadoop, spark, spark, hadoop)

reduce reduce(func: (集合元素类型,集合元素类型) => 集合元素类型): 从左向右聚合 reduce中函数在第一次计算的时候,函数第一个参数的值 = 集合第一个元素 reduce中函数在第N次计算的时候,函数第一个参数的值 = N-1次的计算结果

案例:汇总

代码语言:javascript复制
val list5=List[Int](23,1,2,34,5432,22)
代码语言:javascript复制
val sum=list5.reduce((x,y)=>{x y})
代码语言:javascript复制
println(sum) // 5514

reduceLeftreduce 一样 从左向右聚合

代码语言:javascript复制
val sum=list5.reduceLeft((x,y)=>{x y})
代码语言:javascript复制
println(sum) // 5514

reduceRight reduceRight(func: (集合元素类型,集合元素类型) => 集合元素类型): 从右向左聚合 reduceRight中函数在第一次计算的时候,函数第二个参数的值 = 集合最后一个元素 reduceRight中函数在第N次计算的时候,函数第二个参数的值 = N-1次的计算结果

减法 从 左到右运行

代码语言:javascript复制
val value1=list5.reduceLeft((x,y)=>{x-y})
println(value1) // -5468

减法 从 右到到左运行

代码语言:javascript复制
val value2=list5.reduceRight((x,y)=>{x-y})
println(value2) // 5400

reduce*Option 将结果保存到Option

fold fold(默认值: 集合元素类型)(func: (集合元素类型,集合元素类型)=>集合元素类型):从左向右聚合 fold中的函数在第一次计算的时候,函数第一个参数的值 = 默认值 【与reduce区别的部分】 fold中的函数在第N次计算的时候,函数第一个参数的值 = N-1次的计算结果

代码语言:javascript复制
val list6 = List(1,2,3)
代码语言:javascript复制
val functionToInt = list6.fold(100)((x,y)=>x-y)
代码语言:javascript复制
println(functionToInt) // 94

foldRight foldRight(默认值: B)( func: (集合元素, B) => B ): 从右向左计算 foldRight中的函数在第一次计算的时候,函数第二个参数的值 = 默认值 foldRight中的函数在第N次计算的时候,函数第二个参数的值 = N-1次的计算结果

代码语言:javascript复制
val list6 = List(1,2,3)
代码语言:javascript复制
val functionToInt = list6.foldRight(100)((x,y)=>x-y)
代码语言:javascript复制
println(functionToInt) // -98

0 人点赞