文章目录
集合
Scala都同时提供了可变和不可变的版本
scala.collection.immutable
scala.collection.mutable
数组
不可变数组
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala01_Collection_Array {
def main(args: Array[String]): Unit = {
//Scala-集合-数组
//创建数组对象
//数组的字符串打印:[Ljava.lang.Object;@129a8472
//可以设定泛型,改变数组的类型
//new Array[String](5)编译后会自动生成java的数组代码
//java: String[] array = new String[5];
// array[0]="zhangsan"
val array = new Array[String](5) //[Ljava.lang.String;@3cb5cdba
//向数组中添加数据
//scala中访问数组指定的元素需要采用小括号,而不是中括号
array(0) = "zhangsan"
array(1) = "zhangsan"
array(2) = "zhangsan"
array(3) = "zhangsan"
array(4) = "zhangsan"
//遍历数组中的数据
//可以采用for循环的方式遍历
for (s <- array) { //反编译时foreach
println("s=" + s)
}
//按照规则生成字符串
println(array.mkString(","))
}
}
其他方式创建数组
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala02_Collection_Array {
def main(args: Array[String]): Unit = {
//Scala-集合-数组
//可变集合,不可变集合
//对不可变集合的数据操作会产生新的数组
//Array不可变数组集合
//采用其他的方式创建数组
//apply方法
val array = Array(1, 2, 3, 4)
//添加数据
//使用:+5 表示向数组的后面添加数据
val newArray = array :+ 5
println(array.mkString(",")) //1,2,3,4
println(newArray.mkString(",")) //1,2,3,4,5
//使用+: 表示向数组的前面添加数据
val newArray1 = array.+:(5)
//如果集合的方法采用冒号结尾,那么运算规则从右向左
val newArray2 = 5 +: array //这种就不需要加()需要把array放后面
// array +:5
println(newArray1.mkString(",")) //5,1,2,3,4
println(newArray2.mkString(","))
//++运算符表示增加集合数据(多个数据)
array ++ newArray1
val newArray3 = array :+ "5" //加字符串 变成新数组
println(newArray3.mkString(",")) //1,2,3,4,5
}
}
可变数组
package com.vanas.bigdata.chapter07
import scala.collection.mutable.ArrayBuffer
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala03_Collection_Array {
def main(args: Array[String]): Unit = {
//Scala-集合-数组-可变
//类似于StringBuilder
//可变数组在mutable包中
val array = new ArrayBuffer[String]()
//数据的操作
//追加数据
array.append("a")
array.append("b")
//遍历
for (s <- array) {
println("s=" + s)
}
println(array) //ArrayBuffer(a, b)
println(array.mkString(","))
}
}
Array数组
其他方式创建对象
package com.vanas.bigdata.chapter07
import scala.collection.mutable.ArrayBuffer
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala04_Collection_Array {
def main(args: Array[String]): Unit = {
//Scala-集合-数组-可变
//类似于StringBuilder
//可变数组在mutable包中
// val array = new ArrayBuffer[String]()
val array = ArrayBuffer(1, 2, 3, 4)
//数据的操作
//追加数据,集合内部元素发生改变,所以可变数组
array.append(5)
//向指定位置(索引)插入数据
array.insert(1, 7, 8, 9) //1 7 8 9 2 3 4 5
//对指定的位置(索引)修改数据
// array(1) = 5 ==>编译时,自动转换为update
array.update(1,2) //不要越界
//删除数据
// array.remove(2)
array.remove(2,2) //不可以超出 否则IndexOutOfBoundsException
//遍历
println(array)
println(array.mkString(","))
}
}
总结
package com.vanas.bigdata.chapter07
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
object Scala05_Collection_Array {
def main(args: Array[String]): Unit = {
//Scala
//可变数组
// 内部存储的数据可以动态操作,而不会产生新的集合
// 可变数组提供了大量对数据操作的方法,基本上方法名都是单词
//不可变数组
// 对数据的操作都会产生新的集合
// 提供对数据的操作方法相对来说,比较少,而且都是一些符号
//StringBuilder => String
//可变数组和不可变数组的互相转换
val array = Array(1, 2, 3)
//不可变 =>可变
val buffer: mutable.Buffer[Int] = array.toBuffer
val array1 = ArrayBuffer(1, 2, 3)
//可变=>不可变
val array2: Array[Int] = array1.toArray
}
}
foreach & 数组的操作
package com.vanas.bigdata.chapter07
import scala.collection.mutable.ArrayBuffer
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala06_Collection_Array {
def main(args: Array[String]): Unit = {
//foreach
//循环遍历
val array = Array(1, 2, 3, 4)
// val array = TestArray(1,2,3,4)
def fun(i: Int): Unit = {
println(i)
}
array.foreach(fun)
//至简原则 匿名函数
// array.foreach((i:Int)=>{println(i)})
// array.foreach(i=>println(i))
// array.foreach(println(_))
array.foreach(println)
// 多维数组
var myMatrix = Array.ofDim[Int](3,3)
myMatrix.foreach(list=>list.foreach(println))
// 合并数组
val arr1 = Array(1,2,3,4)
val arr2 = Array(5,6,7,8)
val arr6: Array[Int] = Array.concat(arr1, arr2)
// arr6.foreach(println)
println(arr6.mkString(",")) //这种输出更直观
// 创建指定范围的数组
val arr7: Array[Int] = Array.range(0,2)
//arr7.foreach(println)
println(arr7.mkString(","))
// 创建并填充指定数量的数组
val arr8:Array[Int] = Array.fill[Int](5)(-1)
// arr8.foreach(println)
println(arr8.mkString(","))
}
class TestArray {
val buffer = new ArrayBuffer[Int]()
def foreach(f: Int => Unit): Unit = {
for (i <- buffer) {
f(i)
}
}
}
object TestArray {
def apply(is: Int*) = {
val array = new TestArray()
for (i <- is) {
array.buffer.append(i)
}
array
}
}
}
Seq序列
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala07_Collection_Seq {
def main(args: Array[String]): Unit = {
//Scala -集合 -Seq
//Seq -序列-List
//默认情况下,scala提供的集合都是不可变的,immutable
//默认不可变集合List是抽象类,无法构造对象
//如果想要构造List集合对象,可以采用apply方式
val list = List(1, 2, 3, 4)
//数据处理
val newList: List[Int] = list :+ 5
val newList1: List[Int] = 5 +: list
println(list eq newList) //false
println(list)
println(newList) //List(1, 2, 3, 4, 5)
println(newList1) //List(5, 1, 2, 3, 4)
//遍历数据
println(list.mkString(","))
list.foreach(println)
}
}
Nil
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala08_Collection_Seq {
def main(args: Array[String]): Unit = {
//Scala -集合 -Seq
//空集合(什么数据都加不了)
//Nil = List()
val nil: List[Nothing] = Nil
println(Nil)
//空集合一般用于增加数据
//采用新的方式添加数据
val list: List[Int] = 1 :: 2 :: 3 :: Nil
//Nil::(3)::(2)::(1)=>1,2,3 真实运算顺序 其他语法中动态调用
println(list)
val list1: List[Any] = 4 :: 5 :: list :: Nil
//将一个整体数据拆分成一个一个的个体来使用,称之为扁平化操作 ( ::: )
val list2: List[Any] = 4 :: 5 :: list ::: Nil
println(list1) //List(4, 5, List(1, 2, 3))
println(list2) //List(4, 5, 1, 2, 3)
}
}
可变Seq 增删改
package com.vanas.bigdata.chapter07
import scala.collection.mutable.ListBuffer
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala09_Collection_Seq {
def main(args: Array[String]): Unit = {
//Scala -集合 -Seq-可变
val buffer: ListBuffer[Int] = ListBuffer(1, 2, 3, 4)
//增加数据
buffer.append(5, 6, 7)
buffer.insert(1, 8)
println(buffer)
//修改
//buffer.update(1, 9)
buffer(1) = 9
println(buffer)
//删除数据
buffer.remove(1)
buffer.remove(1,3)
println(buffer)
}
}
Set 数据集
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala10_Collection_Set {
def main(args: Array[String]): Unit = {
//Scala -集合 -Set-集
//默认集合是不可变集合
//java:set 无序不可重复
val set = Set(1, 2, 3, 4)
val newSet: Set[Int] = set + 5
println(set eq newSet)
println(set)
println(newSet)
//Scala Set
//无序:插入顺序 不是数据大小顺序
//不可重复
val set1 = Set(1, 2, 3, 4, 5, 6, 7, 8, 1)
println(set1) //Set(5, 1, 6, 2, 7, 3, 8, 4)
}
}
可变集合
package com.vanas.bigdata.chapter07
import scala.collection.mutable
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala11_Collection_Set {
def main(args: Array[String]): Unit = {
//Scala -集合 -Set-集
//可变集合
//val set = mutable.Set(1, 2, 3, 4, 5, 6, 7, 8)
val set = mutable.Set(1, 2)
println(set)
//添加数据 无序所以没有insert
set.add(3)
// @migration("`+` creates a new set. Use `+=` to add an element to this set and return that set itself.", "2.8.0")
//override def + (elem: A): This = clone() += elem
//产生新的集合
val newSet: mutable.Set[Int] = set + 5
//不会产生新的集合
val oldSet: set.type = set += 5 //这个是在本身操作
println(set eq newSet) //false
println(set eq oldSet) //true
//修改集合
//向集合中添加数据
set.update(3, true)
//从集合中删除数据
set.update(3, false)
//删除数据
set.remove(3)
//@migration("`-` creates a new set. Use `-=` to remove an element from this set and return that set itself.", "2.8.0")
//override def -(elem: A): This = clone() -= elem
set - 2
set -= 2
println(set)
}
}
Map 映射
package com.vanas.bigdata.chapter07
import scala.collection.mutable
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala12_Collection_Map {
def main(args: Array[String]): Unit = {
//Scala -集合 -Map-映射
//A=>B
//K=>V
//map集合用于存储kv对对象
//构建键值对对象
//A->B
//构建对象
//map:无序,key不能重复
// val map: Map[String, Int] = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4, "e" -> 5)
//相同key第二次赋值会覆盖
val map: Map[String, Int] = Map("a" -> 1, "b" -> 2, "c" -> 3, "a" -> 4, "e" -> 5)
println(map)
}
}
可变Map
package com.vanas.bigdata.chapter07
import scala.collection.mutable
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala13_Collection_Map {
def main(args: Array[String]): Unit = {
//apply方法主要用于在伴生对象中构建对象
//Scala -集合 -Map-映射-可变
val map: mutable.Map[String, Int] = mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)
//添加数据
map.put("d", 4)
//修改数据
map.update("d", 5)
map("a") = 6
//删除数据
map.remove("a")
println(map)
}
}
遍历
package com.vanas.bigdata.chapter07
import scala.collection.mutable
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala14_Collection_Map {
def main(args: Array[String]): Unit = {
//apply方法主要用于在伴生对象中构建对象
//Scala -集合 -Map-映射-可变
val map: mutable.Map[String, Int] = mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)
//获取指定key的valuw
//java:map集合可以放null键null值
// map.get(key)
//Option:选项类型
// 有值:Some,根据key可以获取值
// 无值:None,根据key获取不到值
// 主要解决空指针问题
val maybeInt: Option[Int] = map.get("a")
println(maybeInt)
//从None对象中获取值会发生异常
println(maybeInt.get)
//getOrElse方法表示获取数据,如果获取到直接返回,如果获取不到,使用默认值
println(maybeInt.getOrElse(-1)) //没有值 返回一个默认值 -1 用的较多
//maybeInt.isEmpty
//Scala提供了更加简洁的方法
val i: Int = map.getOrElse("a", -1)
println(i)
}
}
元组Tuple
package com.vanas.bigdata.chapter07
import scala.collection.mutable
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala15_Collection_Tuple {
def main(args: Array[String]): Unit = {
//apply方法主要用于在伴生对象中构建对象
//Scala -集合
//1,zhangsan,30
//bean:
//json
//List
//如果将无关的数据当成一个整体来使用
//封装bean,json,集合都不是一个好的选择
//Scala中会采用一种特殊的结构来进行封装
//这个特殊的结构就是采用小括号,称之为元组(元素的组合):Tuple
val data = (1, "zhangsan", 30, "xxxxx")
//Tuple -22
//元组中的数据一般是没有关系的,需要通过数据的顺序访问
//元组中最多能放多少条数据?最多能放22个
//这里的22表示元素的个数,但是不限定元素的类型
//元组对象._顺序号
println(data._1)
println(data._2)
println(data._3)
println(data._4)
//元组遍历
//迭代器
val iterator: Iterator[Any] = data.productIterator
while (iterator.hasNext) {
println(iterator.next())
}
//索引
println(data.productElement(0))
}
}
对偶元组
package com.vanas.bigdata.chapter07
import scala.collection.mutable
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala16_Collection_Tuple {
def main(args: Array[String]): Unit = {
//如果元组中的元素只有2个,这样的元组称之为对偶元组
//也称之为键值对
val data = ("a", 1)
//A->B
//"a" -> 1 //=>("a",1)
val map: mutable.Map[String, Int] = mutable.Map(("a", 1), ("b", 2), ("c", 3))
println(map) //Map(b -> 2, a -> 1, c -> 3)
for (kv <- map) {
println(kv._1 + "=" + kv._2)
}
}
}
集合常用方法
package com.vanas.bigdata.chapter07
import scala.collection.mutable
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala17_Collection_Method {
def main(args: Array[String]): Unit = {
//Scala-集合-常用方法
var list = List(1, 2, 3, 4)
//获取集合的长度 底层size就是length
println(list.length)
println(list.size)
//遍历数据
list.foreach(println)
println(list.mkString(","))
val iterator: Iterator[Int] = list.iterator
//判断是否为空
println(list.isEmpty)
//简单运算
println(list.sum)
println(list.max)
println(list.min)
println(list.product) //乘积
}
}
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala18_Collection_Method {
def main(args: Array[String]): Unit = {
//Scala-集合-常用方法
var list = List(1, 2, 3, 4, 4)
//函数式编程中使用最多的算法其实就是递归算法
//获取集合头
println(list.head) //1
//尾
println(list.tail) //List(2, 3, 4)
//最后一个
println(list.last) //4
//初始
println(list.init) //List(1, 2, 3)
//反转
println(list.reverse)
println(list.reverse.head) //相当于取到了last
//判断数据是否存在
println(list.contains(5))
//数据去重
println(list.toSet)
//底层hashset val seen = new mutable.HashSet[A]()
println(list.distinct)
//取(拿)数据
println(list.take(3))
//从右边拿
println(list.takeRight(3))
//丢弃数据
println(list.drop(2))
println(list.dropRight(2))
}
}
数据操作相关
map 映射
扁平化
扁平化映射
过滤
分组
排序
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala19_Collection_Method {
def main(args: Array[String]): Unit = {
//Scala-集合-常用方法-操作数据
var list = List(1, 2, 3, 4, 5, 6)
//yield
//map:映射转换 A=>B
//100%的需求会用到map
def transform(i: Int): Int = {
i * 2
}
//map方法可以将集合通过指定的转换规则变成新的集合
//指定的转换规则会对集合的每一条数据起作用
// val newList: List[Int] = list.map(transform)
// val newList: List[Int] = list.map((i:Int)=>{i*2})
// val newList: List[Int] = list.map((i:Int)=>i*2)
// val newList: List[Int] = list.map((i)=>i*2)
// val newList: List[Int] = list.map(i=>i*2)
val newList: List[Int] = list.map(_ * 2)
println(newList)
//flatten:扁平化
//所谓的扁平化,其实就是将整体拆分成一个一个的个体使用的方法
//扁平化操作默认只能对外层数据进行操作,内层的数据无法进行操作
//1::list::Nil
val list1 = List(
List(
List(1, 2)
), List(
List(3, 4)
)
)
println(list1.length) //2
//1,2,3,4
println(list1) //List(List(List(1, 2)), List(List(3, 4)))
println(list1.flatten) //List(List(1, 2), List(3, 4))
println(list1.flatten.flatten) //List(1, 2, 3, 4)
//扁平映射 = 扁平化+映射
val list2 = List(
List(1, 2), List(3, 4)
)
println(list2.flatten.map(_ * 2)) //List(2, 4, 6, 8) 这样是先扁平化后映射 分前后2步
//方法中的参数表示集合中的每一个元素
//方法返回的参数类型为可迭代的集合类型
def transform1(list: List[Int]): List[Int] = {
list.map(_ * 2)
}
// println(list2.flatMap(transform1))
// println(list2.flatMap((list)=>{list.map(_*2)}))
// println(list2.flatMap(list=>list.map(_*2)))
println(list2.flatMap(_.map(_*2))) //List(2, 4, 6, 8)
val list3 = List("hello scala", "hello spark")
//String
//println(list3.flatten) 不符合想要的规则
def transfrom2(s: String) = {
s.split(" ").toList
}
println(list3.flatMap(transfrom2))
println(list3.flatMap(_.split(" "))) //List(hello, scala, hello, spark)
//从原理上来讲,做不了扁平化 但是语法满足还是可以做
val list5 = List(1, 2, 3, 4)
println(list5.flatMap((num) => {
List(num * 2)
}))
//过滤
//按照指定的规则对集合中的每一条数据进行筛选过滤
//满足条件的数据保留,不满足条件的数据丢弃
val list6 = List(1,2,3,4)
list6.filter((num)=>{num%2==0})
val list7 = List("hello","spqrk","scala","hadoop")
println(list7.filter(word => {
word.startsWith("s")
})) //List(spqrk, scala)
//分组
//按照指定的规则对集合中的每一个数据进行分组
//指定的规则其实是一个函数,这个函数的返回结果进行分组的key
//分组后数据类型为Map
//map中的key就是分组的key,value就是同一个组的数据集合
val list8 =List(1,2,3,4)
//1%2 =>1
//2%2 =>0
//3%2 =>1
//4%2 =>0
val map: Map[Int, List[Int]] = list8.groupBy(num => {
num % 2
})
println(map) //Map(1 -> List(1, 3), 0 -> List(2, 4))
val list9 = List("hello","spqrk","hello","hadoop")
println(list9.groupBy({
word => {
word
}
})) //Map(hadoop -> List(hadoop), spqrk -> List(spqrk), hello -> List(hello, hello))
//排序
//将集合中每一个数据按照指定规则进行排序
//默认排序为升序
//sortBy可以使用函数柯里化实现降序
val list10 = List(3,1,4,2)
println(list10.sortBy(num => num))
println(list10.sortBy(num => -num)) //特定场合使用 比如数字
println(list10.sortBy(num => num).reverse)
println(list10.sortBy(num => num)(Ordering.Int.reverse))
val list11 = List("1","2","11","4")
//字符串的排序可以按照字典顺序
println(list11.sortBy(s => s)) //List(1, 11, 2, 4)
//"1" =>1
//"2" =>2
//"11"=>11
//"3" =>3
println(list11.sortBy(s => s.toInt)) //List(1, 2, 4, 11)
//自定义类型数据排序
val user1 = new User()
user1.name= "zhangsan"
user1.age=20
val user2 = new User()
user2.name= "lisi"
user2.age=10
val user3 = new User()
user3.name= "wangwu"
user3.age=10
val list12 = List(user1,user2,user3)
//scala中的元组自动比较大小
//先比较第一个元素,再比较第二个元素,以此类推
println(list12.sortBy(user => {
( user.age,user.name)
})) //List(User[lisi,10], User[wangwu,10], User[zhangsan,20])
}
class User{
var name: String = _
var age:Int =_
override def toString: String = {
s"User[$name,$age]"
}
}
}
案例wordcount
分析:
代码:
package com.vanas.bigdata.chapter07
import scala.io.Source
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala20_Collection_WordCount {
def main(args: Array[String]): Unit = {
//scala-WordCount
//需求:将文件中单词统计出现的次数并排序取前三名
//spark=>8wordcount
//所有统计需求,都可以将大的需求拆分成小需求,小需求中基本很多都和wordcount类似
//代码实现:翻译,将文字用代码翻译过来
//1.从文件中获取数据,获取一行一行的字符串
//可迭代的集合都可以互相转换
val dataList: List[String] = Source.fromFile("input/word.txt").getLines().toList
//2.将一行一行字符串拆分成一个一个的单词(分词)
val wordList: List[String] = dataList.flatMap(
data => {
data.split(" ")
}
)
//3.根据单词将数据进行分组:相同的单词放置在一个组中
//Map( (a,List(a,a,a,a)) )
val wordGroupMap: Map[String, List[String]] = wordList.groupBy(
word => word
)
//4.将分组后的数据进行次数统计"(word,count)
//(word,List(word,word,word)=>(word,count)
//A=>B
//键值对对象其实就是Tuple(元组)
val wordToCountMap: Map[String, Int] = wordGroupMap.map(
kv => {
(kv._1, kv._2.length)
}
)
//5.将统计结果根据次数进行排序:降序 //map无序
//Map =>list
val sortList: List[(String, Int)] = wordToCountMap.toList.sortBy(
kv => kv._2
)(Ordering.Int.reverse)
//6.将排序后的结果取前3名:top3
val result: List[(String, Int)] = sortList.take(3)
println(result)
}
}
wordcount代码简化
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala21_Collection_WordCount {
def main(args: Array[String]): Unit = {
//scala-WordCount
val dataList = List("hello spark scala hive")
//简化
val result: List[(String, Int)] = dataList
.flatMap(_.split(" "))
.groupBy(word => word)
.map(kv => (kv._1, kv._2.size))
.toList
.sortBy(_._2)
.take(3)
println(result)
}
}
Scala的练习作业:
数据 :
List(
(“hello”, 4),
(“hello spark”, 3),
(“hello spark scala”, 2),
(“hello spark scala hive”, 1)
)
要求 : 1. 将上面的数据进行WordCount后排序取前三名!
2.使用2种不同的方式。
方式一:
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala22_Collection_WordCount {
def main(args: Array[String]): Unit = {
//scala-WordCount
val list= List(
("hello", 4),
("hello spark", 3),
("hello spark scala", 2),
("hello spark scala hive", 1)
)
//字符串可以重复出现
val dataList: List[String] = list.map(kv => {(kv._1 + " ") * kv._2})
val result: List[(String, Int)] = dataList
.flatMap(_.split(" "))
.groupBy(word => word)
.map(kv => (kv._1, kv._2.size))
.toList
.sortBy(_._2)
.take(3)
println(result)
}
}
方式二:
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala23_Collection_WordCount {
def main(args: Array[String]): Unit = {
//scala-WordCount
//("hello", 4)
//("hello", 3),("spark", 3)
//("hello", 2),("spark", 2),("scala", 2)
//("hello", 1),("spark", 1),("scala", 1),("hive", 1)
val list = List(
("hello", 4),
("hello spark", 3),
("hello spark scala", 2),
("hello spark scala hive", 1)
)
//数据进行扁平化操作
val wordToCountList: List[(String, Int)] = list.flatMap(
kv => {
//将字符串进行分词
val str = kv._1
val count = kv._2
val words: Array[String] = str.split(" ")
//将原有数据转换为新的数据格式
//word=>(word,count)
words.map(
word => (word, count)
)
}
)
//将相同单词分在一个组中
val wordToListMap: Map[String, List[(String, Int)]] = wordToCountList.groupBy(_._1)
//将数据进行结构的转换
//hello=>List(("hello",4),("hello",3),("hello",2)("hello",1))
//hello=>List(4,3,2,1)
//hello=>List.sum=>10
// val wordToSumMap: Map[String, Int] = wordToListMap.map(kv => {
// val word: String = kv._1
// val list: List[(String, Int)] = kv._2
// val countlist: List[Int] = list.map(_._2)
// val sum = countlist.sum
// (word, sum)
// })
//在kv数据处理过程中,如果k保持不变,只对v进行处理,可以采用特殊的方法
val wordToSumMap: Map[String, Int] = wordToListMap.mapValues(
v => {
val ints: List[Int] = v.map(_._2)
ints.sum
}
)
val result =wordToSumMap
.toList
.sortBy(_._2)(Ordering.Int.reverse)
.take(3)
println(result)
}
}
Q&A
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala24_Collection_QA {
def main(args: Array[String]): Unit = {
val list = List("hello", "hello")
//匿名函数的位置,下划线的作用
//1.代替参数出现一次,直接写下划线
//2.下划线可以将函数作为整体进行传递
//3.如果匿名函数的参数不参与逻辑处理,可以使用下划线省略
def groupFunction(s: String): String = {
s
}
//list.flatMap(list=>list)
//如果匿名函数中逻辑处理直接返回参数本身,那么不要使用下划线省略参数
//val stringToStrings: Map[String, List[String]] = list.groupBy(word => word)
//val stringToStrings = list.groupBy(_) //error
list.foreach(println(_)) //Any 所以println特殊可以传输
//flatMap(list => list)什么意思?
val dataList = List(
List(1, 2), List(3, 4)
)
println(dataList.flatMap(list => list)) //List(1, 2, 3, 4)
// val list1 = List(1, 2, List(3, 4))
// list1.flatMap(
// data => {
// //模拟匹配
// if (data.isInstanceOf[List]) {
// data.asInstanceOf[List] //iterator
// } else {
// List(data)
// }
// }
// )
自定义排序
//排序
val ints = List(1, 4, 3, 2)
val ints1 = List("1", "3", "2")
val ints2 = List((30, "zhangsan"), (20, "wangwu"), (20, "lisi"))
println(ints.sortBy(num => num))
println(ints1.sortBy(s => s.toInt))
println(ints2.sortBy(t => t)) //tuple本身就有序
println(ints2.sortBy(t => t)(Ordering.Tuple2(Ordering.Int.reverse, Ordering.String))) //List((30,zhangsan), (20,lisi), (20,wangwu))
//自定义排序
//两两比较大小
//大>小=>降序
//小<大=>升序
//sortWith默认的比较规则就是小于:升序
//sortWith:用于判断左边数据是否小于右边数据
// 如果满足(true),升序,不满足(false)就是降序
//实现时,只需要考虑满足我们自定义条件的场合下,返回true就可以
//lt =>less than
//升序:true 降序:falas
println(ints2.sortWith( //List((30,zhangsan), (20,lisi), (20,wangwu))
(left, right) => {
//升序
//当满足你的排序要求时,你就返回true
//当不满足你的排序要求时,你就返回fals
//left._1>right._1 //降序
// left._1 < right._1 //升序
if (left._1 > right._1) { //升序
true
} else if (left._1 == right._1) {
left._2 < right._2
} else {
false
}
}
))
}
}
交差合集 拉链 滑动
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala25_Collection_Method {
def main(args: Array[String]): Unit = {
//Scala-集合-常用方法-操作数据
//对多个集合数据进行处理
val list1 = List(1, 2, 3, 4)
val list2 = List(3, 4, 5, 6)
val list3 = List(3, 4, 5, 6, 7)
//并集,合集
//1,2,3,4,3,4,5,6
println(list1.union(list2))
//交集:交叉的数据
//3, 4
println(list1.intersect(list2))
//差集:当前集合减去交叉重合的数据
//1,2
println(list1.diff(list2))
//5,6
println(list2.diff(list1))
//两个集合数据进行关联:相同位置的关联
//如果两个集合的元素个数不相同,那么拉链后的数据取决于个数少的那个集合
//拉链
//(1,3), (2,4), (3,5), (4,6)
val zipList: List[(Int, Int)] = list1.zip(list2)
println(zipList) //List((1,3), (2,4), (3,5), (4,6))
val zipList2: List[(Int, Int)] = list1.zip(list3)
println(zipList2 //List((1,3), (2,4), (3,5), (4,6))
//自关联:索引和索引关联
//val ziplist1: List[(Int, Int)] = list1.zip(list1) //没意义
//val ziplist1: List[(Int, Int)] = list1.map(num => (num, num))
//一般做索引关联
val list4 = List("a", "b", "c", "d")
val ziplist1: List[(String, Int)] = list4.zipWithIndex
//val ziplist1: List[(Int, Int)] = list1.zipWithIndex
println(ziplist1) //List((a,0), (b,1), (c,2), (d,3))
//将数据的一部分作为整体来使用操作的函数
val list = List(1, 2, 3, 4, 5, 6, 7, 8)
//取得集合中每3条连续的数据和
//滑动窗口:数据指定的范围进行滑动
// 可以将这个范围称之为窗口
//参数中的size表示窗口的数据长度
//参数中的step表示窗口滑动的幅度(步长)
val iterator: Iterator[List[Int]] = list.sliding(3)
while (iterator.hasNext){
println(iterator.next().sum)
}
val iterator1: Iterator[List[Int]] = list.sliding(3,3)
while (iterator1.hasNext){
println(iterator1.next())
}
}
}
计算相关
简化规约reduce
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala26_Collection_Method {
def main(args: Array[String]): Unit = {
//Scala-集合-常用方法-操作数据
//计算
val list = List(1, 2, 3, 4)
//mapReduce
//简化,规约
//reduce参数 op:(A1,A1)=>A1
//reduce中传递的参数的规则:参数和返回值类型相同
//这里的参数其实就是集合中数据的类型
//scala中集合的计算基本上都是两两计算
//val i: Int = list.reduce((a:Int,b:Int)=>{a+b})
//val i: Int = list.reduce((a:Int,b:Int)=>a+b)
//val i: Int = list.reduce((a,b)=>a+b)
val i: Int = list.reduce(_ + _)
println(i) //10
// var sum = 0
// for (i<-list){
// sum =sum+i
// }
// println(sum)
//从源码的角度,reduce操作其实就是reduceLeft
//reduceLeft参数: op:(B,Int)=>B
//这里的参数B,应该和Int类型有关系,才能使用
val i1: Int = list.reduceLeft(_ - _)
println(i1) //-8
//reduceRight参数: op:(Int,B)=>B
val i2: Int = list.reduceRight(_ - _)
println(i2) //-2
//如果是list(1,2,3,4,5)的话reduceRight(_-_) 结果是 3
}
}
折叠fold
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala28_Collection_Method {
def main(args: Array[String]): Unit = {
//scala -集合-常用方法 -折叠
//将集合之外的数据和集合内部的数据进行聚合的操作,称之为折叠
//聚合数据的方式依然为两两操作
val dataList=List(1,2,3,4)
//fold方法存在函数柯里化,有2个参数列表
//第一个参数列表中的参数=>z:A1 [z为zero,表示数据处理的初始值]
//第二个参数列表中的参数=>(A1,A1)=>A1 [聚合数据的逻辑]
//fold方法在进行数据处理时,外部的数据应该和集合内部的数据类型保持一致
val i: Int = dataList.fold(10)(_ - _)
//从源码的角度讲,fold方法的底层其实就是foldLeft
//ford,fordleft,fordRight方法返回值类型为初始值类型
val str: String = dataList.foldLeft("")(_ + _) //1234
// reverse.foldLeft(z)((right, left) => op(left, right))
val i1: Int = dataList.foldRight(5)(_ + _) //15
val str1: String = dataList.foldRight("a")(_ + _)//1234a
println(str1)
}
}
合并
package com.vanas.bigdata.chapter07
import scala.collection.mutable
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala29_Collection_Method {
def main(args: Array[String]): Unit = {
//scala -集合-合并集合
//Map(a->1,b->2,c->3)
//Map(a->4,d->5,c->6)
//=>
//Map(a->5,b->2,d->5,c->9)
val map1 = mutable.Map("a"->1,"b"->2,"c"->3)
val map2 = mutable.Map("a"->4,"d"->5,"c"->6)
//reduce只能对集合内部的数据进行聚合操作 zip少了数据也不行
//map1.a => map2.a => map2.a(1+4)
val result: mutable.Map[String, Int] = map1.foldLeft(map2) {
(map, kv) => { //kv 来自map1 ,map来自map2
val k: String = kv._1
val v: Int = kv._2
// val newVal: Int = map.getOrElse(k, 0) + v
// map(k) = newVal
map.update(k,map.getOrElse(k,0)+v)
map
}
}
println(result) //Map(b -> 2, d -> 5, a -> 5, c -> 9)
println(map1) //Map(b -> 2, a -> 1, c -> 3)
println(map2) //Map(b -> 2, d -> 5, a -> 5, c -> 9)
val result2: mutable.Map[String, Int] = map2.foldLeft(map1) {
(map, kv) => {
val k: String = kv._1
val v: Int = kv._2
// val newVal: Int = map.getOrElse(k, 0) + v
//map(k) = newVal
map.update(k,map.getOrElse(k,0)+v)
map
}
}
println(result2) //Map(b -> 4, d -> 5, a -> 6, c -> 12)
// foldLeft[B](z: B)(op: (B, A) => B): B
//注意 foldLeft()谁在括号里 谁是map也就会改变
}
}
扫描scan
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala30_Collection_Method {
def main(args: Array[String]): Unit = {
//scala -集合-合并集合
val list = List(1, 2, 3, 4)
//fold方法直接获取最终的结果
//scan类似于fold方法,但是会将中间的处理结果也保留下来
//集合扫描
//0,1,3,6,10
println(list.scan(0)(_ + _))
//集合扫描(左)
println(list.scanLeft(0)(_ + _))
//集合扫描(右)
//List(10, 9, 7, 4, 0)
println(list.scanRight(0)(_ + _)) //List(10, 9, 7, 4, 0)
}
}
队列
package com.vanas.bigdata.chapter07
import scala.collection.mutable
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala31_Collection_Queue {
def main(args: Array[String]): Unit = {
//BlockingQueue(阻塞式队列) 节点通信用的较多
//Deque(双端队列)
//Kafka 如何保证数据有序 用的就是双端队列 可以在两端取放
val que = new mutable.Queue[String]()
// 添加元素
que.enqueue("a", "b", "c")
val que1: mutable.Queue[String] = que += "d"
println(que eq que1)
// 获取元素
println(que.dequeue())
println(que.dequeue())
println(que.dequeue())
}
}
并行
并行与并发区别
scala提供并行操作
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala32_Collection_Par {
def main(args: Array[String]): Unit = {
// val ints=List(1,2,3)
// ints.foreach(println)
//串行
// val result1 = (0 to 100).map{x => Thread.currentThread.getName}
// println(result1)
val result2 = (0 to 100).par.map{x => Thread.currentThread.getName}
println(result2)
}
}
什么是线程安全问题?
共享同一个对象 存在安全问题
对象不共享解决了安全问题
package com.vanas.bigdata.java.chapter07;
/**
* @author Vanas
* @create 2020-05-29 4:00 下午
*/
public class Java01_ThreadSafe {
public static void main(String[] args) {
final User user = new User();
Thread t1 = new Thread(new Runnable() {
public void run() {
user.name = "zhangsan";
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(user.name);
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
user.name = "lisi";
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(user.name);
}
});
t1.start();
t2.start();
System.out.println("main方法执行完毕");
//1.总共几个线程?
// t1,t2,main
//2.哪个线程休眠了?
// t1(1000),t2(1000)
//3.哪个线程在执行
//main
//4.打印顺序
//main方法执行完毕
//lisi
//lisi
//所谓的线程安全问题,其实就是多线程并发时
// 对共享内存中共享对象的属性进行修改所导致的数据冲突问题
//1.线程串行 能解决 但不推荐 效率太低
//2.让对象内存不共享(栈)
//3.让对象不共享,多例对象
//4.调用对象的方法不会出现线程安全问题,因为压栈操作是独享操作
//5.如果只是访问属性,而不是修改属性,那么也不会出现线程安全问题
}
}
class User{
public String name;
}
练习
不同省份(当中)商品点击排行
package com.vanas.bigdata.chapter07
/**
* @author Vanas
* @create 2020-05-26 3:56 下午
*/
object Scala33_Collection_Test {
def main(args: Array[String]): Unit = {
//不同省份(当中)商品点击排行
//(item count)=>(word,count)
val datalist = List(
("zhangsan", "河北", "鞋"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "鞋"),
("zhangsan", "河南", "鞋"),
("lisi", "河南", "衣服"),
("wangwu", "河南", "鞋"),
("zhangsan", "河南", "鞋"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "鞋"),
("zhangsan", "河北", "鞋"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "帽子"),
("zhangsan", "河南", "鞋"),
("lisi", "河南", "衣服"),
("wangwu", "河南", "帽子"),
("zhangsan", "河南", "鞋"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "帽子"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "电脑"),
("zhangsan", "河南", "鞋"),
("lisi", "河南", "衣服"),
("wangwu", "河南", "电脑"),
("zhangsan", "河南", "电脑"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "帽子")
)
//数据会存在多余的内容,应该将数据进行清洗
// ("wangwu", "河北", "帽子") =>("河北","帽子") =>("河北-帽子")
val list: List[String] = datalist.map(
t => {
(t._2 + "-" + t._3)
}
)
//应该在统计数据时,根据省份和商品同时进行分组
//group ("河北-帽子")=>("河北-帽子",count)
val dataToListMap: Map[String, List[String]] = list.groupBy(data => data)
val dataToCoutMap: Map[String, Int] = dataToListMap.mapValues(_.size)
//将分组聚合后的数据进行结构的转换
//如果改变数据结构时,可能会导致key重复,那么不要使用map结构
// ("河北-帽子",count)=>(河北,(帽子,count))
// ("河北-帽子",count)=>(河北,(衣服,count))
val prvToItemAndCountList: List[(String, (String, Int))] = dataToCoutMap.toList.map(
kv => {
val k = kv._1
val count = kv._2
//将key进行拆分
val ks = k.split("-")
(ks(0), (ks(1), count)) //map中不能有相同key
}
)
//将分组聚合后的数据根据省份进行分组
//(河北,List[(帽子,count),(衣服,count),(鞋,count)])
val groupMap: Map[String, List[(String, (String, Int))]] = prvToItemAndCountList.groupBy(_._1)
//将分组后的数据进行排序:降序
val result: Map[String, List[(String, Int)]] = groupMap.mapValues(list => {
val itemToCountList: List[(String, Int)] = list.map(_._2)
itemToCountList.sortWith(
(left, right) => {
left._2 > right._2
}
)
})
println(result)
}
}
//Map(河南 -> List((鞋,6), (衣服,3), (电脑,2), (帽子,1)), 河北 -> List((衣服,6), (鞋,4), (帽子,3), (电脑,1)))