zoukankan      html  css  js  c++  java
  • Scala集合的操作

    [toc]

    ## Scala集合的操作

    ### 1. 集合元素的映射操作

    > 1. 看一个实际需求
    > - 要求:请将List(3,5,7) 中的所有元素都 * 2 ,将其结果放到一个新的集合中返回,即返回一个新的List(6,10,14), 请编写程序实现。
    > - 上面提出的问题,其实就是一个关于集合元素映射操作的问题。
    > 2. `在Scala中可以通过map映射操作来解决:将集合中的每一个元素通过指定功能(函数)映射(转换)成新的`
    > 3. `结果集合这里其实就是所谓的将函数作为参数传递给另外一个函数,这是函数式编程的特点。`
    > 4. 以HashSet为例说明:
    > 1. `def map[B](f: (A) ⇒ B): HashSet[B]` //map函数的签名
    > 2. 这个就是map映射函数集合类型都有
    > 3. [B] 是泛型
    > 4. `map 是一个高阶函数`(可以接受一个函数的函数,就是高阶函数)
    > 5. HashSet[B] 就是返回的新的集合
    > 5. 主要学习map和flatmap这两种映射操作。

    #### 传统方式解决

    ~~~~scala
    /**
    * @Date 2021/4/2 14:32
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MapOperateDemo01 {
    def main(args: Array[String]): Unit = {
    /**
    * 请将List(3,5,7) 中的所有元素都 * 2
    * 将其结果放到一个新的集合中返回,
    * 即返回一个新的List(6,10,14), 请编写程序实现
    */

    val list1 = List(3, 5, 7) //集合
    var list2 = List[Int]() //新的集合,准备放入新的内容

    for (item <- list1) {
    // 对元素*2 ,然后加入list2集合
    list2 = list2 :+ item * 2
    }

    println("list2=" + list2) //List(6,10,14)

    /**
    * 对上面传统的方法来解决问题的小结
    * 1. 优点
    * (1) 处理方法比较直接,好理解
    * 2. 缺点
    * (1) 不够简洁,高效
    * (2) 没有体现函数式编程特点: 集合——>函数——>新的集合——>函数
    * (3) 不利于处理复杂的数据处理业务
    */
    }
    }
    ~~~~

    #### map映射函数解决

    > 我们首先需要搞明白什么是高阶函数,下面我们看两个案例
    >
    > 案例一:

    ~~~~scala
    /**
    * @Date 2021/4/2 14:41
    * @Version 10.21
    * @Author DuanChaojie
    */
    object HighOrderFunDemo01 {
    def main(args: Array[String]): Unit = {
    // 高阶函数的学习
    // 可以把一个函数直接赋给一个变量,但是不执行函数 _
    val fun = myPrint _
    fun()

    /**
    * 请将List(3,5,7) 中的所有元素都 * 2
    * 将其结果放到一个新的集合中返回
    * 即返回一个新的List(6,10,14), 请编写程序实现
    **/
    val res = test(sum, 3.5)
    println("res = " + res)

    }

    /**
    * 普通的函数
    */
    def myPrint(): Unit = {
    println("Hello Scala!")
    }

    /**
    * 高阶函数
    * @param fun 该方法可以接收一个函数,其函数可以接收Double,返回Double
    * @param n1 普通参数Double类型
    * @return fun(n1) 执行你传入的函数
    */
    def test(fun: Double => Double, n1: Double) = {
    fun(n1)
    }

    /**
    * 普通的函数
    * @param d 接受一个Double
    * @return 返回Double
    */
    def sum(d: Double): Double = {
    d + d
    }
    }
    ~~~~

    > 案例二:

    ~~~~scala
    /**
    * @Date 2021/4/2 15:01
    * @Version 10.21
    * @Author DuanChaojie
    */
    object HighOrderFunDemo02 {
    def main(args: Array[String]): Unit = {
    test(sayOk)
    }

    /**
    * 高阶函数,可以接受一个没有输入,返回为Unit的函数
    * @param fun
    */
    def test(fun: () => Unit) = {
    fun()
    }

    def sayOk() = {
    println("say Ok~~~")
    }

    def sub(n1: Int): Unit = {
    }
    }
    ~~~~

    > 真正搞懂高阶函数,并使用高阶函数解决上述问题:

    ~~~~scala
    package com.atguigu.chapter11

    /**
    * @Date 2021/4/2 15:09
    * @Version 10.21
    * @Author DuanChaojie
    */
    object MapOperateDemo02 {
    def main(args: Array[String]): Unit = {
    val list1 = List(3, 5, 7, 9)

    /**
    * 请将List(3,5,7) 中的所有元素都 * 2
    * 将其结果放到一个新的集合中返回,
    * 即返回一个新的List(6,10,14), 请编写程序实现
    *
    * 说明 list.map(multiple) 做了什么
    * 1. 将list这个集合的元素 依次遍历
    * 2. 将各个元素传递给 multiple 函数 => 新Int
    * 3. 将得到新Int ,放入到一个新的集合并返回
    * 4. 因此multiple 函数调用3
    */
    val list2 = list1.map(multiple)

    // list2 = List(6, 10, 14, 18)
    println("list2 = " + list2)


    //深刻理解map映射函数的机制-模拟实现
    val myList1 = MyList()
    val myList2 = myList1.map(multiple)
    println("myList2 = " + myList2)
    }

    def multiple(n: Int): Int = {
    2 * n
    }
    }

    /**
    * 深刻理解map映射函数的机制-模拟实现
    */
    class MyList {
    val list1 = List(3, 5, 7, 9)
    // 新的集合
    var list2 = List[Int]()

    // 写map
    def map(f: Int => Int): List[Int] = {
    // 遍历集合
    for (item <- this.list1) {
    list2 = list2 :+ (item * 2)
    }
    list2
    }
    }

    object MyList {
    def apply(): MyList = new MyList()
    }
    ~~~~

    #### map课堂练习

    > 请将`val names = List("dd","mm","dm")`中所有的单词,全部转成字母大写,返回到新的List集合中

    ~~~~scala
    /**
    * @Date 2021/4/2 15:21
    * @Version 10.21
    * @Author DuanChaojie
    */
    object Exercise01 {
    def main(args: Array[String]): Unit = {
    /**
    * 请将val names = List("dd","mm","dm")中所有的单词,全部转成字母大写,返回到新的List集合中
    */
    val names = List("dd", "mm", "dm")
    val list2 = names.map(upper)
    // list2 = List(DD, MM, DM)
    println("list2 = " + list2)
    }

    def upper(str: String): String = {
    str.toUpperCase
    }
    }
    ~~~~

    #### flatmap映射

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

    ~~~~scala
    /**
    * @Date 2021/4/2 15:25
    * @Version 10.21
    * @Author DuanChaojie
    */
    object FlatMapDemo01 {
    def main(args: Array[String]): Unit = {
    val names = List("dd", "mm", "dm")

    // 将List集合中的所有元素,进行扁平化操作,即把所有的元素打散
    val names2 = names.flatMap(upper)
    // names2 = List(D, D, M, M, D, M)
    println("names2 = " + names2)

    }


    def upper(str: String): String = {
    str.toUpperCase
    }
    }
    ~~~~

    ### 2. 集合的一系列操作

    对集合元素的操作主要有==过滤filter,化简reduce,折叠fold,扫描scan,拉链zip,迭代器==

    #### 过滤filter

    > 1. `filter:将符合要求的数据(筛选)放置到新的集合中。`
    > 2. 应用案例:将 `val names = List("Alice", "Bob", "Nick")` 集合中首字母为'A'的筛选到新的集合。

    ~~~~scala
    /**
    * @Date 2021/4/2 16:30
    * @Version 10.21
    * @Author DuanChaojie
    */
    object FilterDemo01 {
    def main(args: Array[String]): Unit = {
    /**
    * 选出首字母为A的元素
    */
    val names = List("Alice", "Bob", "Nick")
    val names2 = names.filter(startA)

    println("names=" + names)
    println("names2=" + names2)

    }

    def startA(str:String): Boolean = {
    str.startsWith("A")
    }

    }
    ~~~~

    #### 化简reduce

    > 1. `化简:将二元函数引用于集合中的函数。`
    > 2. 看一个需求:`val list = List(1, 20, 30, 4 ,5)` , 求出list的和。
    > 3. 上面的问题当然可以使用遍历list方法来解决,这里我们使用Scala的化简方式来完成。

    ~~~~scala
    /**
    * @Date 2021/4/2 16:39
    * @Version 10.21
    * @Author DuanChaojie
    */
    object ReduceDemo01 {
    def main(args: Array[String]): Unit = {
    /**
    * 使用化简的方式来计算list集合的和
    */
    val list = List(1, 20, 30, 4, 5)
    // 接收一个函数时,也可以直接传入一个匿名函数
    val res = list.reduceLeft(sum)

    //执行的流程分析
    //步骤 1 (1 + 20)
    //步骤 2 (1 + 20) + 30
    //步骤 3 ((1 + 20) + 30) + 4
    //步骤 4 (((1 + 20) + 30) + 4) + 5 = 60
    println("res=" + res) // 60
    }

    def sum(n1: Int, n2: Int): Int = {
    /**
    * 1 + 20 = 21
    * 21 + 30 = 51
    * 51 + 4 = 55
    * 55 + 5 = 60
    */
    println(s"$n1 + $n2 = ${n1 + n2}")
    n1 + n2
    }
    }
    ~~~~

    > 对`reduceLeft`的运行机制的说明:
    >
    > 1. `def reduceLeft[B >: A](@deprecatedName('f) op: (B, A) => B): B`
    > 2. ``reduceLeft(f) 接收的函数需要的形式为 op: (B, A) => B): B`
    > 3. `reduceleft(f)` 的运行规则是 从左边开始执行将得到的结果返回给第一个参数,然后继续和下一个元素运行,将得到的结果继续返回给第一个参数,继续...
    >
    > 化简的课堂练习:

    ~~~~scala
    package com.atguigu.chapter11

    /**
    * @Date 2021/4/2 16:44
    * @Version 10.21
    * @Author DuanChaojie
    */
    object ReduceExercise01 {
    def main(args: Array[String]): Unit = {
    val list = List(1, 2, 3, 4, 5)

    /** (((1-2) - 3) - 4) - 5 = -13
    * 1 - 2 = -1
    * -1 - 3 = -4
    * -4 - 4 = -8
    * -8 - 5 = -13
    */
    println(list.reduceLeft(minus))

    /** 1 - (2 - (3 -(4 - 5))) = 3
    * 4 - 5 = -1
    * 3 - -1 = 4
    * 2 - 4 = -2
    * 1 - -2 = 3
    */
    println(list.reduceRight(minus))

    // reduce等价于 reduceLeft
    println(list.reduce(minus))

    // 求list中的最小值 1
    println(list.reduce(min))

    }

    def minus(n1: Int, n2: Int): Int = {
    println(s"$n1 - $n2 = ${n1 - n2}")
    n1 - n2
    }

    def min(n1: Int, n2: Int): Int = {
    if (n1 > n2) {
    n2
    } else {
    n1
    }
    }

    }
    ~~~~

    #### 折叠fold

    > fold函数将上一步返回的值作为函数的第一个参数继续传递参与运算,直到list中的所有元素被遍历。
    >
    > 可以把reduceLeft看做简化版的foldLeft,如何理解:
    >
    > ~~~~scala
    > override /*TraversableLike*/
    > def reduceLeft[B >: A](@deprecatedName('f) op: (B, A) => B): B =
    > if (isEmpty) {
    > throw new UnsupportedOperationException("empty.reduceLeft")
    > }else {
    > tail.foldLeft[B](head)(op)
    > }
    > ~~~~
    >
    > 大家可以看到`reduceLeft`就是调用的`foldLeft[B](head)`,并且是默认从集合的head元素开始操作的。
    >
    > 相关函数:`fold,foldLeft,foldRight`,可以参考reduce的相关方法理解。

    ~~~~scala

    /**
    * @Date 2021/4/2 16:51
    * @Version 10.21
    * @Author DuanChaojie
    */
    object FoldDemo01 {
    def main(args: Array[String]): Unit = {
    val list = List(1, 2, 3, 4)


    /**
    * 说明
    * 1. 折叠的理解和化简的运行机制几乎一样.
    * 理解 list.foldLeft(5)(minus) 理解成 list(5,1, 2, 3, 4) list.reduceLeft(minus)
    */

    //步骤 (5-1)
    //步骤 ((5-1) - 2)
    //步骤 (((5-1) - 2) - 3)
    //步骤 ((((5-1) - 2) - 3)) - 4 = - 5

    println(list.foldLeft(5)(minus)) // 函数的柯里化

    // 理解 list.foldRight(5)(minus) 理解成 list(1, 2, 3, 4, 5) list.reduceRight(minus)
    // 步骤 (4 - 5)
    // 步骤 (3- (4 - 5))
    // 步骤 (2 -(3- (4 - 5)))
    // 步骤 1- (2 -(3- (4 - 5))) = 3
    println(list.foldRight(5)(minus))
    }

    def minus(n1: Int, n2: Int): Int = {
    n1 - n2
    }
    }
    ~~~~

    > `foldLeft和foldRight 缩写方法分别是:/:和:\`

    ~~~~scala

    /**
    * @Date 2021/4/2 16:54
    * @Version 10.21
    * @Author DuanChaojie
    */
    object FoldDemo02 {
    def main(args: Array[String]): Unit = {
    val list = List(1, 9)

    // 这种写法等价于 val res1 = list.foldLeft(4)(minus)
    val res1 = (4 /: list) (minus)
    println("res1 = " + res1) // -6

    // 这种写法等价于 val res1 = list.foldRight(5)(minus)
    val res2 = (list :\ 5) (minus)
    println("res2 = " + res2) // -3
    }

    def minus(n1: Int, n2: Int): Int = {
    n1 - n2
    }
    }
    ~~~~

    #### 扫描scan

    扫描,即对某个集合的所有元素做fold操作,但是会把产生的所有中间结果放置于一个集合中保存。

    ~~~~scala
    /**
    * @Date 2021/4/2 16:59
    * @Version 10.21
    * @Author DuanChaojie
    */
    object ScanDemo01 {
    def main(args: Array[String]): Unit = {
    val res1 = (1 to 5).scanLeft(5)(minus)
    // res1 = Vector(5, 4, 2, -1, -5, -10)
    println("res1 = " + res1)


    val res2 = (1 to 5).scanRight(5)(add)
    // res2 = Vector(20, 19, 17, 14, 10, 5)
    println("res2 = " + res2)


    }


    def minus(n1: Int, n2: Int): Int = {
    n1 - n2
    }

    def add(n1: Int, n2: Int): Int = {
    n1 + n2
    }
    }
    ~~~~

    #### 拉链zip

    > 在开发中,当我们需要将两个集合进行 对偶元组合并,可以使用拉链。

    ~~~~scala
    /**
    * @Date 2021/4/2 18:13
    * @Version 10.21
    * @Author DuanChaojie
    */
    object ZipDemo01 {
    def main(args: Array[String]): Unit = {
    // 拉链
    val list1 = List(1, 2, 3)
    val list2 = List(4, 5, 6)
    val res = list1.zip(list2)
    println("res = " + res)

    println("-------------遍历---------------")
    for (item <- res) {
    println(item._1 + "——" + item._2)
    }
    }
    }
    ~~~~

    > 注意事项:
    >
    > 1. 拉链的本质就是两个集合的合并操作,合并后每个元素是一个 对偶元组。
    >
    > 2. 操作的规则下图:
    >
    > ![image-20210402200926045](assets/image-20210402200926045.png)
    >
    > 3. 如果两个集合个数不对应,会造成数据丢失。
    >
    > 4. 集合不限于List, 也可以是其它集合比如 Array
    >
    > 5. 如果要取出合并后的各个对偶元组的数据,可以遍历

    #### 迭代器iterator

    > 通过iterator方法从集合获得一个迭代器,通过while循环和for表达式对集合进行遍历(学习使用迭代器来遍历)

    ~~~~scala
    /**
    * @Date 2021/4/2 18:17
    * @Version 10.21
    * @Author DuanChaojie
    */
    object IteratorDemo01 {
    def main(args: Array[String]): Unit = {
    // 获得迭代器
    val iterator = List(1, 2, 3, 4).iterator

    println("-------------------遍历方式一 while------------------------")

    /**
    * while (iterator.hasNext) {
    * println(iterator.next())
    * }
    */
    println("-------------------遍历方式一 for------------------------")
    for (item <- iterator) {
    println(item)
    }

    /** 这里我们看看iterator 的继承关系
    * def iterator: Iterator[A] = new AbstractIterator[A] {
    * var these = self
    * def hasNext: Boolean = !these.isEmpty
    * def next(): A = if (hasNext) {val result = these.head; these = these.tail; result} else Iterator.empty.next()
    * // ......
    * }
    */

    }
    }
    ~~~~

    > 迭代器小结:
    >
    > 1. iterator 的构建实际是 AbstractIterator 的一个匿名子类
    > 2. 该AbstractIterator 子类提供了 hasNext 和 next 等方法
    > 3. 因此,我们可以使用 while的方式,使用hasNext 和 next 方法遍历

    #### 集合综合应用案例

    > 练习一:`val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD"`,将sentence 中各个字符,通过foldLeft存放到 一个ArrayBuffer中。

    ```scala
    /**
    * @Date 2021/4/2 17:04
    * @Version 10.21
    * @Author DuanChaojie
    */
    object Exercise02 {
    def main(args: Array[String]): Unit = {
    val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD"
    val arrayBuffer = new ArrayBuffer[Char]()

    // 理解折叠的第一个传入的arrayBuffer 含义
    sentence.foldLeft(arrayBuffer)(putArray)
    println("arrayBuffer=" + arrayBuffer)
    }

    def putArray(arr: ArrayBuffer[Char], c: Char): ArrayBuffer[Char] = {
    //将c 放入到arr 中
    arr.append(c)
    arr
    }
    }
    ```

    > 练习二:`val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD"`,使用映射集合,统计一句话中,各个字母出现的次数。
    >
    > Java实现的版本:
    >
    > ~~~~java
    > package com.atguigu.chapter11;
    >
    > import java.util.HashMap;
    > import java.util.Map;
    >
    > /**
    > * @Date 2021/4/2 17:08
    > * @Version 10.21
    > * @Author DuanChaojie
    > */
    > public class JavaExercise {
    > public static void main(String[] args) {
    > // 统计各个字母出现的次数
    > String sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD";
    >
    > Map map = new HashMap<Character, Integer>();
    >
    > char[] chars = sentence.toCharArray();
    >
    > for (int i = 0; i < chars.length; i++) {
    > char temp = chars[i];
    > if (map.containsKey(temp)) {
    > Integer count = (Integer) map.get(temp);
    > map.put(temp, count + 1);
    > } else {
    > map.put(temp, 1);
    > }
    > }
    > // {A=10, B=8, C=5, D=7}
    > System.out.println(map);
    > }
    > }
    > ~~~~
    >
    > Scala实现的版本:

    ~~~~scala
    /**
    * @Date 2021/4/2 17:16
    * @Version 10.21
    * @Author DuanChaojie
    */
    object Exercise03 {
    def main(args: Array[String]): Unit = {
    val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD"
    val map1 = Map[Char, Int]()

    // 先创建一个可变map,作为左折叠的第一个参数
    val res1 = sentence.foldLeft(map1)(charCount1)
    //res1 = Map(A -> 10, B -> 8, C -> 5, D -> 7)
    println("res1 = " + res1)

    // 使用可变的map效率更高
    val map2 = mutable.Map[Char, Int]()
    val res2 = sentence.foldLeft(map2)(charCount2)
    // res2 = Map(D -> 7, A -> 10, C -> 5, B -> 8)
    println("res2 = " + res2)
    }

    /**
    * @param map 不可变的map
    * @param char
    * @return
    */
    def charCount1(map: Map[Char, Int], char: Char): Map[Char, Int] = {
    map + (char -> (map.getOrElse(char, 0) + 1))
    }

    /**
    * @param map 可变的map
    * @param char
    * @return
    */
    def charCount2(map: mutable.Map[Char, Int], char: Char): mutable.Map[Char, Int] = {
    map += (char -> (map.getOrElse(char, 0) + 1))
    }
    }
    ~~~~

    > 练习三:大数据中经典的`wordcount`案例:`val lines = List("atguigu han hello ", "atguigu han aaa aaa aaa ccc ddd uuu")`,使用映射集合,list中,各个单词出现的次数,并按出现次数排序。

    ```scala
    import scala.collection.mutable

    /**
    * @Date 2021/4/2 17:42
    * @Version 10.21
    * @Author DuanChaojie
    */
    object Exercise04 {
    def main(args: Array[String]): Unit = {
    val lines = List("atguigu han hello", "atguigu han aaa aaa aaa ccc ddd uuu")
    val res = lines.foldLeft(mutable.Map[String, Int]())(wordCount)
    // _._1 根据key排序,_._2根据value排序,默认都是升序
    //println(res.toSeq.sortBy(_._2))
    println(res.toSeq.sortWith(_._2 > _._2))
    }

    def wordCount(map: mutable.Map[String, Int], str: String): mutable.Map[String, Int] = {
    val strs = str.split(" ")
    for (word <- strs) {
    if (map.contains(word)) {
    val count = map.get(word).get
    map += (word -> (count + 1))
    } else {
    map += (word -> 1)
    }
    }
    map
    }

    }
    ```

    > 解决方案二:

    ~~~~scala
    package com.atguigu.chapter11

    /**
    * @Date 2021/4/2 20:22
    * @Version 10.21
    * @Author DuanChaojie
    */
    object Exercise05 {
    def main(args: Array[String]): Unit = {
    val lines = List("atguigu han hello ", "atguigu han aaa aaa aaa ccc ddd uuu")

    val res1 = lines.flatMap(_.split(" "))
    println("res1=" + res1)
    /**
    * 1. 使用map,返回对偶元组 形式为
    * List((hello,1), (tom,1), (hello,1), (jerry,1), (hello,1), (jerry,1), (hello,1), (kitty,1))
    */
    val res2 = res1.map((_, 1))
    println("res2=" + res2)

    /**
    * res2.groupBy(_._1)
    * 1. 分组的根据是以元素来分组
    * 2. _._1 中的第一个 _ 表示取出的各个对偶元组比如 (hello,1)
    * 3. _._1 中的_1, 表示对偶元组的第一个元素,比如 hello
    * 4. 因此 _._1 表示我们分组的标准是按照对偶元组的第一个元素进行分组
    * 5. 返回的形式为 Map(tom -> List((tom,1)), kitty -> List((kitty,1)), jerry -> List((jerry,1), (jerry,1)), hello -> List((hello,1), (hello,1), (hello,1), (hello,1)))
    */
    val res3 = res2.groupBy(_._1)
    println("res3=" + res3)

    /**
    * x=>(x._1, x._2.size) 传入一个匿名函数,完成统计
    * 1.x 表示传入的Map中的各个元素,比如 jerry -> List((jerry,1), (jerry,1))
    * 2.x._1 表示 jerry
    * 3.x._2.size,表示对 List((jerry,1), (jerry,1))求size,是多少就是多少
    * 4.结果是 res4=Map(han -> 2, atguigu -> 2, hello -> 1)
    * 5.到此结果就出来了,但是没有排序
    */
    val res4 = res3.map(x=>(x._1, x._2.size))
    println("res4=" + res4 )

    /**
    * res4.toList.sortBy(_._2)
    * 1. toList先将map转成 list,为了下一步排序
    * 5. sortBy就是排序,以对偶元组的第二个值排序,就是大小排序
    */
    val res5 = res4.toList.sortBy(_._2)
    println("res5=" + res5)

    //如果希望从大到小排序,执行reverse即可
    val res6 = res5.reverse
    }
    }
    ~~~~

    ### 3. 集合的扩展知识

    ==流Stream,视图View,并行集合par,操作符==

    #### 流Stream

    > 1. Stream是一个集合,这个集合可以用于存放无穷多个元素,但是这个无穷个元素并不会一次性生产出来,而是需要用到多大的区间,就会动态的生产,`末尾元素遵循lazy规则`(即:要使用结果才进行计算的)。
    > 2. 创建Stream:`def stream(n: BigInt): Stream[BigInt] = n #:: stream(n + 1)`
    > 3. 说明:
    > 1. Stream 集合存放的数据类型是`BigInt`
    > 2. stream是自定义的一个函数,函数名是程序员指定的。
    > 3. 创建的集合的第一个元素是 n , 后续元素生成的规则是 n + 1
    > 4. 后续元素生成的规则是可以程序员指定的 ,比如 `stream( n * 4)...`
    > 5. 如果使用流集合,就不能使用last属性,如果使用last集合就会进行无限循环

    ~~~~scala
    /**
    * @Date 2021/4/2 18:25
    * @Version 10.21
    * @Author DuanChaojie
    */
    object StreamDemo01 {
    def main(args: Array[String]): Unit = {
    // 创建Stream
    def stream(n: BigInt): Stream[BigInt] = n #:: stream(n + 1)

    val stream1 = stream(1)
    println(stream1)
    // 取出第一个元素
    println("stream1.head = " + stream1.head)

    // 当对流执行tail操作时,就会生成一个新的数据
    println("stream1.tail = " + stream1.tail)
    println(stream1)

    }
    }
    ~~~~

    #### 视图View

    > Stream的懒加载特性,也可以对其他集合应用view方法来得到类似的效果,具有如下特点:
    >
    > 1. view方法产出一个总是被懒执行的集合。
    > 2. view不会缓存数据,每次都要重新计算,比如遍历View时。
    >
    > 请找到1-100 中,数字倒序排列 和它 本身相同的所有数。

    ~~~~scala
    /**
    * @Date 2021/4/2 18:30
    * @Version 10.21
    * @Author DuanChaojie
    */
    object ViewDemo01 {
    def main(args: Array[String]): Unit = {
    // 没有使用view
    val res1 = (1 to 100).filter(eq)
    // res = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99)
    println("res1 = " + res1)

    /**
    * 使用view,来完成这个问题,程序中,对集合进行map,filter,reduce,fold...
    * 你并不希望立即执行,而是在使用到结果才执行,则可以使用view来进行优化.
    */
    val res2 = (1 to 100).view.filter(eq)
    // res2 = SeqViewF(...)
    println("res2 = " + res2)

    for (item <- res2) {
    print(item + "\t")
    }
    println("\nres2 = " + res2)
    }


    def eq(n: Int): Boolean = {
    n.toString.equals(n.toString.reverse)
    }
    }
    ~~~~

    > 所有线程安全的集合都是以Synchronized开头的集合:
    >
    > 1. SynchronizedBuffer
    > 2. SynchronizedMap
    > 3. SynchronizedPriorityQueue
    > 4. SynchronizedQueue
    > 5. SynchronizedSet
    > 6. SynchronizedStack

    #### 并行集合par

    > Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。
    >
    > 主要用到的算法有:
    >
    > 1. Divide and conquer : 分治算法,Scala通过splitters(分解器),combiners(组合器)等抽象层来实现,主要原理是将计算工作分解很多任务,分发给一些处理器去完成,并将它们处理结果合并返回
    > 2. Work stealin算法【学数学】,主要用于任务调度负载均衡(load-balancing),通俗点完成自己的所有任务之后,发现其他人还有活没干完,主动(或被安排)帮他人一起干,这样达到尽早干完的目的。

    ~~~scala
    /**
    * @Date 2021/4/2 18:57
    * @Version 10.21
    * @Author DuanChaojie
    */
    object ParDemo01 {
    def main(args: Array[String]): Unit = {
    (1 to 5).foreach(println(_))
    println()
    (1 to 5).foreach(println(_))

    val res1 = (0 to 100).map { case_ => Thread.currentThread().getName }.distinct
    val res2 = (0 to 100).par.map { case_ => Thread.currentThread().getName }.distinct

    println("res1 = " + res1)
    println("res2 = " + res2)
    }
    }
    ~~~

    #### 操作符

    > 这部分内容没有必要刻意去理解和记忆,语法使用的多了,自然就会熟练的使用,该部分内容了解一下即可。
    >
    > 1. 如果想在变量名、类名等定义中使用语法关键字(保留字),可以配合反引号反引号
    >
    > ~~~~scala
    > val `val` = 42
    > ~~~~
    >
    > 2. 中置操作符:`A 操作符 B` 等同于 `A.操作符(B)`
    > 3. 后置操作符:`A操作符` 等同于 `A.操作符`,如果操作符定义的时候不带()则调用时不能加括号
    > 4. 前置操作符,`+、-、!、~等操作符A`等同于`A.unary_操作符`
    > 5. 赋值操作符,`A 操作符= B` 等同于 `A = A 操作符 B` ,比如 A += B 等价 A = A + B

    ~~~~scala
    package com.atguigu.chapter11

    /**
    * @Date 2021/4/2 19:02
    * @Version 10.21
    * @Author DuanChaojie
    */
    object OperatorDemo01 {
    def main(args: Array[String]): Unit = {
    val n1 = 1
    val n2 = 2
    val res1 = n1 + n2
    println("res1 = " + res1)
    val res2 = n1.+(n2)
    println("res2 = " + res2)

    // 测试操作的重载
    val monster = new Monster
    monster + 10
    monster.+(10)

    println("monster.money=" + monster.money) // 20

    {
    monster ++
    }
    {
    monster.++
    }

    println("monster.money=" + monster.money) // 22

    !monster
    println("monster.money=" + monster.money) // -22
    }
    }

    class Monster {
    var money: Int = 0

    // 对操作符进行重载(中置操作符)
    def +(n: Int): Unit = {
    this.money += n
    }

    //对操作符进行重载(后置操作符)
    def ++(): Unit = {
    this.money += 1
    }

    //对操作符进行重载(前置操作符,一元运算符)
    def unary_!(): Unit = {
    this.money = -this.money
    }
    }
    ~~~~

    ## ☆

  • 相关阅读:
    Mongoose使用
    Koa原理和封装
    微信用户授权
    Koa微信公众号开发
    Koa2+mongoose
    NodeJS-API
    jquery下json数组的操作用法实例
    SqlCacheDependency:asp.net SQL缓存依赖
    SqlCacheDependency轮询数据库表的更改情况的频率
    设置浏览器地址栏URL前面显示的图标
  • 原文地址:https://www.cnblogs.com/huaobin/p/15764424.html
Copyright © 2011-2022 走看看