集合用法
1. 集合概述
1.1 简介
- Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质。对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本。
- Seq:是一个有先后次序的值的序列,比如数组或列表。IndexSeq允许我们通过它们的下标快速的访问任意元素。举例来说,ArrayBuffer是带下标的,但是链表不是。
- Set:是一组没有先后次序的值。在SortedSet中,元素以某种排过序顺序被访问。
- Map:是一组(键、值)对。SortedMap按照键的排序访问其中的实体。
1.2 可变集合
-
可变集合可以在适当的地方被更新或扩展。这意味着你可以修改,添加,移除一个集合的元素。
-
scala.collection.immutable
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0LUUC6OQ-1655393424628)(assets/1648536124515.png)]
1.3 不可变集合
-
不可变集合类,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变,所以这里的不可变并不是变量本身的值不可变,而是变量指向的那个内存地址不可变可变集合和不可变集合,在scala中该如何进行区分呢?我们一般可以根据集合所在包名进行区分:
-
scala.collection.mutable
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mJl1lurh-1655393424629)(assets/1648536092474.png)]
2. 数组用法
2.1 不可变数组
2.1.1 数组特点
-
Scala默认提供的集合都是不可变。
-
scala中给数组一个特定的类型:Array
-
可以根据索引访问数组的元素,中括号在scala中表示泛型,所以不能在索引操作中使用,使用小括号
2.1.2 数组定义
// String[]
// 构建Scala中的数组,其实等同于构造Java的数组
val array = new Array[String](3)
// 使用集合的伴生对象构建集合,并同时初始化
val array1 = Array(1,2,3,4)
val array2 = Array(5,6,7,8)
//val array2 = Array.apply(1,2,3,4)
2.1.3 数组访问
- 可以根据索引访问数组的元素
// 访问
// 可以根据索引访问数组的元素
//array.update(1, "abc")
// 中括号在scala中表示泛型,所以不能在索引操作中使用,使用小括号
array(1) = "abc"
2.1.4 数组遍历
for ( i <- array ) {
println(i)
}
// foreach方法是一个循环的方法,需要传递一个参数,这个从参数的类型是函数类型
// 函数类型 : Int => U
def foreachFunction(num:Int): Unit = {
println(num)
}
//array1.foreach(foreachFunction)
//array1.foreach((num:Int)=>{println(num)})
//array1.foreach((num:Int)=>println(num))
//array1.foreach((num)=>println(num))
//array1.foreach(num=>println(num))
array1.foreach(println(_))
2.1.5 运算符操作
package com.gec.demo2
object ScalaDemo {
def main(args: Array[String]): Unit = {
//定义不可变数组
val array1 = Array(1,2,3,4)
val array2 = Array(5,6,7,8)
//调用+:方法,参数为5,将参数5添加到数组数据前面
val ints_1: Array[Int] = array1.+:(5)
//调用+:方法,参数为5
val ints_2=5+:array1
println(ints_1.mkString(","))
println(ints_2.mkString(","))
//调用:+方法,参数为5,将参数5添加到数组数据后面
val ints_3 = array1.:+(5)
val ints_4=array1:+5
println(ints_3.mkString(","))
println(ints_4.mkString(","))
}
}
2.2 可变数组
2.2.1 概述
- 导入scala.collection.mutable.ArrayBuffer这个类
2.2.2 用法
package com.gec.demo
import scala.collection.mutable.ArrayBuffer
object Scala02_Collection {
def main(args: Array[String]): Unit = {
// TODO - 集合 - 数组 - 可变数组
//val buffer = new ArrayBuffer[String]()
val buffer = ArrayBuffer("a", "b", "c")
println(buffer)
// TODO 操作
//buffer.append("a", "b", "c", "d")
// buffer.appendAll(Array("a", "b", "c"))
//buffer.insert(7, "f")
//buffer.update(0, "e")
//buffer(0) = "e"
//buffer.remove(2)
//buffer.remove(2,2)
val strings: ArrayBuffer[String] = buffer - "a"
println(buffer eq strings)
println(buffer)
println(strings)
}
}
2.3 可变数组和不可变数组转换
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
object ScalaCollection{
def main(args: Array[String]): Unit = {
val buffer = ArrayBuffer(1,2,3,4)
val array = Array(4,5,6,7)
// 将不可变数组转换为可变数组
val buffer1: mutable.Buffer[Int] = array.toBuffer
// 将可变数组转换为不可变数组
val array1: Array[Int] = buffer.toArray
}
}
3. Seq集合
3.1 不可变List
- 有序、可重复的数据
3.1.1 如何创建List集合
object ScalaCollection{
def main(args: Array[String]): Unit = {
// Seq集合
val list = List(1,2,3,4)
// 增加数据
val list1: List[Int] = list :+ 1
println(list1 eq list)
list1.foreach(println)
val list2: List[Int] = 1 +: list
list2.foreach(println)
println("*****************")
val list3: List[Int] = list.updated(1,5)
println(list eq list3)
List3.foreach(println)
}
}
3.1.2 基本操作
// 数据操作
val ints: List[Int] = list :+ 5
val ints1: List[Int] = 5 +: list
ints.foreach(println)
println("---------------")
ints1.foreach(println)
3.2 可变List
3.2.1 基本语法
import scala.collection.mutable.ListBuffer
object ScalaCollection{
def main(args: Array[String]): Unit = {
// 可变集合
val buffer = new ListBuffer[Int]()
// 增加数据
buffer.append(1,2,3,4)
// 修改数据
buffer.update(1,3)
// 删除数据
buffer.remove(2)
buffer.remove(2,2)
// 获取数据
println(buffer(1))
// 遍历集合
buffer.foreach(println)
}
}
3.2.2 基本操作
import scala.collection.mutable.ListBuffer
object ScalaCollection{
def main(args: Array[String]): Unit = {
// 可变集合
val buffer1 = ListBuffer(1,2,3,4)
val buffer2 = ListBuffer(5,6,7,8)
// 增加数据
val buffer3: ListBuffer[Int] = buffer1 :+ 5
val buffer4: ListBuffer[Int] = buffer1 += 5
val buffer5: ListBuffer[Int] = buffer1 ++ buffer2
val buffer6: ListBuffer[Int] = buffer1 ++= buffer2
println( buffer5 eq buffer1 )
println( buffer6 eq buffer1 )
val buffer7: ListBuffer[Int] = buffer1 - 2
val buffer8: ListBuffer[Int] = buffer1 -= 2
println( buffer7 eq buffer1 )
println( buffer8 eq buffer1 )
}
}
3.2.3 可变集合和不可变集合转换
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
object ScalaCollection{
def main(args: Array[String]): Unit = {
val buffer = ListBuffer(1,2,3,4)
val list = List(5,6,7,8)
// 可变集合转变为不可变集合
val list1: List[Int] = buffer.toList
// 不可变集合转变为可变集合
val buffer1: mutable.Buffer[Int] = list.toBuffer
}
}
3.3 Set集合
3.3.1 不可变Set
3.3.1.1 创建不可变的Set
object ScalaCollection{
def main(args: Array[String]): Unit = {
val set1 = Set(1,2,3,4)
val set2 = Set(5,6,7,8)
}
}
3.3.1.2 基本操作
object ScalaCollection{
def main(args: Array[String]): Unit = {
val set1 = Set(1,2,3,4)
val set2 = Set(5,6,7,8)
// 增加数据
val set3: Set[Int] = set1 + 5 + 6
val set4: Set[Int] = set1.+(6,7,8)
println( set1 eq set3 ) // false
println( set1 eq set4 ) // false
set4.foreach(println)
// 删除数据
val set5: Set[Int] = set1 - 2 - 3
set5.foreach(println)
val set6: Set[Int] = set1 ++ set2
set6.foreach(println)
println("********")
val set7: Set[Int] = set2 ++: set1
set7.foreach(println)
println(set6 eq set7)
}
}
3.3.2 可变Set
3.3.2.1 基本语法
import scala.collection.mutable
object ScalaCollection{
def main(args: Array[String]): Unit = {
val set1 = mutable.Set(1,2,3,4)
val set2 = mutable.Set(5,6,7,8)
// 增加数据
set1.add(5)
// 添加数据
set1.update(6,true)
println(set1.mkString(","))
// 删除数据
set1.update(3,false)
println(set1.mkString(","))
// 删除数据
set1.remove(2)
println(set1.mkString(","))
// 遍历数据
set1.foreach(println)
}
}
3.3.2.2 基本操作
import scala.collection.mutable
object ScalaCollection{
def main(args: Array[String]): Unit = {
val set1 = mutable.Set(1,2,3,4)
val set2 = mutable.Set(4,5,6,7)
// 交集
val set3: mutable.Set[Int] = set1 & set2
println(set3.mkString(","))
// 差集
val set4: mutable.Set[Int] = set1 &~ set2
println(set4.mkString(","))
}
}
3.4 Map集合
3.4.1 概述
- Map(映射)是一种可迭代的键值对(key/value)结构。所有的值都可以通过键来获取。Map 中的键都是唯一的。
3.4.2 不可变Map
3.4.2.1 创建map对象
object ScalaCollection{
def main(args: Array[String]): Unit = {
val map1 = Map( "a" -> 1, "b" -> 2, "c" -> 3 )
val map2 = Map( "d" -> 4, "e" -> 5, "f" -> 6 )
}
}
3.4.2.2 运算符操作
package com.gec.demo2
import scala.collection.mutable
object ScalaDemo {
def main(args: Array[String]): Unit = {
// 创建空集合
val empty: Map[String, Int] = Map.empty
val map2=empty.+(("001",1000),("002",2000),("003",3000))
val map3 = Map( "d" -> 4, "e" -> 5, "f" -> 6 )
println(map2)
val map4=map2.++:(map3)
println(map4)
val map5=map2.++(map3)
println(map5)
val map6=map3.++(map2)
println(map6)
}
}
object ScalaCollection{
def main(args: Array[String]): Unit = {
val map1 = Map( "a" -> 1, "b" -> 2, "c" -> 3 )
val map2 = Map( "d" -> 4, "e" -> 5, "f" -> 6 )
// 创建空集合
val empty: Map[String, Int] = Map.empty
println(empty)
// 获取指定key的值
val i: Int = map1.apply("c")
println(i)
println(map1("c"))
// 获取可能存在的key值
val maybeInt: Option[Int] = map1.get("c")
// 判断key值是否存在
if ( !maybeInt.isEmpty ) {
// 获取值
println(maybeInt.get)
} else {
// 如果不存在,获取默认值
println(maybeInt.getOrElse(0))
}
// 获取可能存在的key值, 如果不存在就使用默认值
println(map1.getOrElse("c", 0))
}
}
3.4.3 可变的map对象
3.4.3.1 基本用法
package com.gec.demo
import scala.collection.mutable
object ScalaCollection_5 {
def main(args: Array[String]): Unit = {
val map1 = mutable.Map( "a" -> 1, "b" -> 2, "c" -> 3 )
val map2 = mutable.Map( "d" -> 4, "e" -> 5, "f" -> 6 )
// 添加数据
map1.put("d", 4)
val map3: mutable.Map[String, Int] = map1 + ("e" -> 4)
println(map1 eq map3)
val map4: mutable.Map[String, Int] = map1 += ("e" -> 5)
println(map1 eq map4)
// 修改数据
map1.update("e",8)
map1("e") = 8
// 删除数据
map1.remove("e")
val map5: mutable.Map[String, Int] = map1 - "e"
println(map1 eq map5)
val map6: mutable.Map[String, Int] = map1 -= "e"
println(map1 eq map6)
// 清除集合
map1.clear()
}
}
3.4.3.2 遍历操作
import scala.collection.mutable
object ScalaCollection{
def main(args: Array[String]): Unit = {
val map1 = mutable.Map( "a" -> 1, "b" -> 2, "c" -> 3 )
val map2 = mutable.Map( "d" -> 4, "e" -> 5, "f" -> 6 )
val set: Set[(String, Int)] = map1.toSet
val list: List[(String, Int)] = map1.toList
val seq: Seq[(String, Int)] = map1.toSeq
val array: Array[(String, Int)] = map1.toArray
println(set.mkString(","))
println(list.mkString(","))
println(seq.mkString(","))
println(array.mkString(","))
println(map1.get("a"))
println(map1.getOrElse("a", 0))
println(map1.keys)
println(map1.keySet)
println(map1.keysIterator)
println(map1.values)
println(map1.valuesIterator)
}
}
4. 元组
4.1 概述
- 在Scala语言中,我们可以将多个无关的数据元素封装为一个整体,这个整体我们称之为:元素组合,简称元组。有时也可将元组看成容纳元素的容器,其中最多只能容纳22个
4.2 用法
object ScalaCollection{
def main(args: Array[String]): Unit = {
// 创建元组,使用小括号
val tuple = (1, "zhangsan", 30)
// 根据顺序号访问元组的数据
println(tuple._1)
println(tuple._2)
println(tuple._3)
// 迭代器
val iterator: Iterator[Any] = tuple.productIterator
// 根据索引访问元素
tuple.productElement(0)
// 如果元组的元素只有两个,那么我们称之为对偶元组,也称之为键值对
val kv: (String, Int) = ("a", 1)
val kv1: (String, Int) = "a" -> 1
println( kv eq kv1 )
}
}
5. 集合方法
5.1 简单方法
// TODO - 集合 - 方法
val array = Array(1,2,3,4)
println(array.size)
println(array.length)
println(array.isEmpty)
println(array.contains(2))
println(array.distinct.mkString(","))
println(array.reverse.mkString(","))
println(array.mkString(","))
array.foreach(println)
array.iterator
5.2 reduce
-
集合的数据无论是多少,最基本的数据操作其实都是两两计算。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J5IE4yH6-1655393424629)(assets/1648543677144.png)]
// TODO - 集合 - 方法 val array = ArrayBuffer(1,2,3,4, 5) // 自定义数据操作的方法 // 集合的数据无论是多少,最基本的数据操作其实都是两两计算。 // map => reduce => 简化,规约(聚合) def reduceFunction(x : Int, y : Int): Int = { x + y } //println(array.reduce(reduceFunction)) //println(array.reduce((x:Int, y:Int)=>{x + y})) //println(array.reduce((x:Int, y:Int)=>x + y)) //println(array.reduce((x, y)=>x + y)) println(array.reduce(_ - _)) // -13
5.3 折叠方法
-
fold方法
- 折叠, 对集合数据进行简化, 获取最终的一条结果fold方法传递2个部分的参数, 第一个部分表示集合之外的数据, 第二个部分的参数表示数据进行的逻辑处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3QETkxx-1655393424630)(assets/1648782998467.png)]
package com.gec.demo3 import scala.collection.mutable import scala.collection.mutable.ArrayBuffer object Scala02_Collection { def main(args: Array[String]): Unit = { val array = ArrayBuffer(1,2,3,4) val num = 5 println(array.fold(5)(_ + _)) } }
5.4 map方法
-
功能函数:由集合对象提供函数执行自定义的功能,map => 映射(转换) => K->V
def main(args: Array[String]): Unit = { // TODO - 集合 - 方法 val array = ArrayBuffer(1,2,3,4) // TODO 功能函数:由集合对象提供函数执行自定义的功能 // 1. map => 映射(转换) => K->V // a => b // map方法需要传递一个参数,这个参数的类型为函数类型: Int => B def mapFunction( num:Int ): Int = { num * 2 } //println(array.map(mapFunction)) // println(array.map( // (num:Int) => { // num * 2 // } // )) println(array.map(_*2)) }
5.5 flatMap方法
-
将整体拆分成个体的操作,称之为扁平化,扁平化操作只能对最外层进行操作
val array = Array( "Hello Scala", "Hello Hadoop" ) //println(array.flatten.mkString(",")) println(array.flatMap( str => { str.split(" ") } ).mkString(","))
5.6 filter方法
-
filter方法可以对集合中的每一条数据进行筛选过滤
// TODO - 集合 - 方法 val array = ArrayBuffer(1,2,3,4) // filter方法可以对集合中的每一条数据进行筛选过滤 // 满足条件(true)的数据保留,不满足条件(false)的数据丢弃 val r = array.filter( num => { num % 2 != 0 } ) println(r)
5.7 groupBy方法
-
根据指定的规则对每一条数据进行分组
// TODO - 集合 - 方法 // val array = ArrayBuffer(1,2,3,4) // // // 根据指定的规则对每一条数据进行分组 // val r = array.groupBy( // num => { //// if ( num % 2 == 0 ) { //// "偶数" //// } else { //// "奇数" //// } // num % 2 // } // ) // // println(r) val array = ArrayBuffer( "Hello", "Scala", "Hadoop", "Spark" ) println(array.groupBy(_.substring(0, 1)))
5.8 sortBy
-
排序:通过指定的规则对每一条数据进行排序处理, 默认为升序
// TODO - 集合 - 方法 //val array = ArrayBuffer(1,4,2,3) val array = ArrayBuffer("1", "11", "2", "3", "22") // 排序:通过指定的规则对每一条数据进行排序处理, 默认为升序 println(array.sortBy( num => num.toInt ))
6. 综合实例
6.1 需求
- 统计单词出现次数
6.2 如何实现
package com.gec.bigdata.scala.chapter07
import scala.collection.mutable.ArrayBuffer
import scala.io.{BufferedSource, Source}
object Scala05_Collection_WordCount {
def main(args: Array[String]): Unit = {
// TODO 1. 读取文件,获取原始数据
// line => Hello Scala
val source: BufferedSource = Source.fromFile("data/word.txt")
val lines: Array[String] = source.getLines().toArray
source.close()
// TODO 2. 将原始数据进行切分成一个一个的单词
// "Hello Scala" => "Hello", "Scala"
val words = lines.flatMap(
line => {
line.split(" ")
}
)
// TODO 3. 对分词的结果进行分组操作(相同的单词放置在一起)
// "Hello", "Hello" => { "Hello"=>List( Hello, Hello ) }
val wordGroup: Map[String, Array[String]] = words.groupBy(word => word)
// TODO 4. 对分组后的数据进行数量的统计
// 如果数据在转换时,无需对key进行操作,只对v进行处理时,可以使用mapValues方法
// { "Hello"=>List( Hello, Hello ) }
// =>
// { "Hello"=>2 }
val wordCount = wordGroup.mapValues(
v => {
v.size
}
)
// TODO 5. 将统计结果打印在控制台
println(wordCount)
}
}
6.3 优化写法
package com.gec.bigdata.scala.chapter07
import scala.io.{BufferedSource, Source}
object Scala05_Collection_WordCount_1 {
def main(args: Array[String]): Unit = {
// TODO 1. 读取文件,获取原始数据
// line => Hello Scala
val source: BufferedSource = Source.fromFile("data/word.txt")
val lines: Array[String] = source.getLines().toArray
source.close()
val wordCount =
lines
.flatMap(_.split(" "))
.groupBy(word => word)
.mapValues(_.size)
println(wordCount)
}
}
val wordCount = wordGroup.mapValues(
v => {
v.size
}
)
// TODO 5. 将统计结果打印在控制台
println(wordCount)
}
}
## 6.3 优化写法
~~~ scala
package com.gec.bigdata.scala.chapter07
import scala.io.{BufferedSource, Source}
object Scala05_Collection_WordCount_1 {
def main(args: Array[String]): Unit = {
// TODO 1. 读取文件,获取原始数据
// line => Hello Scala
val source: BufferedSource = Source.fromFile("data/word.txt")
val lines: Array[String] = source.getLines().toArray
source.close()
val wordCount =
lines
.flatMap(_.split(" "))
.groupBy(word => word)
.mapValues(_.size)
println(wordCount)
}
}