Scala 集合篇笔记(三)

集合

Scala都同时提供了可变和不可变的版本

scala.collection.immutable

image-20200526205911052

scala.collection.mutable

img

数组

不可变数组

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

分析:

截屏2020-05-27 下午8.03.47

代码:

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)

截屏2020-05-29 下午8.04.20

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

交差合集 拉链 滑动

截屏2020-05-29 下午8.19.39

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

截屏2020-05-29 下午8.26.30

计算相关

简化规约reduce

截屏2020-05-29 下午8.32.41

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

截屏2020-05-29 下午8.35.42

折叠fold

截屏2020-05-29 下午8.46.15

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

合并

截屏2020-05-29 下午8.56.36

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也就会改变 
    }
}

截屏2020-05-29 下午9.08.21

扫描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())
    }
}

并行

并行与并发区别

截屏2020-05-29 下午9.15.07

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

什么是线程安全问题?

共享同一个对象 存在安全问题

截屏2020-05-29 下午9.22.38

对象不共享解决了安全问题

截屏2020-05-29 下午9.18.28

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)))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值