13_Scala_数据结构下_集合操作

举报
alexsully 发表于 2021/05/08 17:32:27 2021/05/08
【摘要】 map映射 flatmap filter 化简reduce 折叠 fold 扫描 scan 拉链 zip 迭代器  iterator stream & view

高阶函数

object HighOrderT1 {
  def main(args: Array[String]): Unit = {
    //在scala中,可以把一个函数直接赋给一个变量,但是不执行函数 (myPrint _)
    val m1 = myPrint _
    println(m1  ) //com.chapter11_Array_Func.HighOrderT1$$$Lambda$1/1149319664@17ed40e0
    m1()  //执行 myPrint() 输出 hello

   //函数直接赋给一个变量,但是不执行函数 addSum _
    val i = Htest(addSum _, 30)
    println(i) //60
    Htest2(myPrint)   //hello
  }

  def myPrint(): Unit = {
    println("hello")
  }

  def Htest (f: Int=> Int, num: Int) = {
    f(num)
  }

  def addSum (i: Int) : Int = {
    i * 2
  }

 //说明Htest2是一个高阶函数,可以接受一个 没有输入,返回为Unit的函数
  def Htest2(f: ()=>Unit): Unit = {
    f()
  }}

map映射操作

在Scala中通过map映射解决:集合中的每一个元素通过指定功能(函数)映射(转换)成新集合

将函数作为参数传递给另外一个函数,这是函数式编程的特点

object MapTest1 {
  def main(args: Array[String]): Unit = {
    val list1 = List(10,20,30,40)

    //1. 将list1这个集合的元素 依次遍历 将各个元素传递给 multiple 函数 => 新Int
    //2. 将得到新Int ,放入到一个新的集合并返回 multiple 函数调用4次
    val list2 = list1.map(multiple)
    println(list2)  //List(20, 40, 60, 80)

    //1. 将names这个集合的元素 依次遍历 将各个元素传递给 stringTrans 函数 => 新String
    //2. 将得到新String ,放入到一个新的集合并返回 names_new
    val names = List("Alex", "Bob", "Sully")
    val names_new = names.map(stringTrans)
    println(names_new) //List(ALEX, BOB, SULLY)

  }

  def multiple(n:Int): Int = {
    println("multiple 被调用~~")
    2 * n}

  def stringTrans(s: String) : String ={
    s.toUpperCase()}

}

flatmap:flat即压扁,压平,扁平化,效果就是将集合中的每个元素的子元素映射到某个函数并返回新的集合
filter:将符合要求的数据(筛选)放置到新的集合中;  filter 要求函数返回 boolean

object MapTest1 {
  def main(args: Array[String]): Unit = {
    val list1 = List(10,20,30,40)

    //1. 将list1这个集合的元素 依次遍历 将各个元素传递给 multiple 函数 => 新Int
    //2. 将得到新Int ,放入到一个新的集合并返回 multiple 函数调用4次
    val list2 = list1.map(multiple)
    println(list2)  //List(20, 40, 60, 80)

    //1. 将names这个集合的元素 依次遍历 将各个元素传递给 stringTrans 函数 => 新String
    //2. 将得到新String ,放入到一个新的集合并返回 names_new
    //  A => B  String => B
    val names = List("Alex", "Bob", "Sully")
    val names_new = names.map(stringTrans)
    println(names_new) //List(ALEX, BOB, SULLY)

   // flatmap 将集合中的每个元素的子元素映射到某个函数并返回新的集合
   // 进行扁平化操作,即把所有元素打散
    // A => IterableOnce[B]   string => IterableOnce[B]
    val names_flat = names.flatMap(stringTrans)

    println(names_flat) //List(A, L, E, X, B, O, B, S, U, L, L, Y)


    // Filter A => Boolean  A 泛型; String => Boolean
    // 数据(筛选)放置到新的集合中
    val names_filter = names.filter(stringeql)
    println(names_filter) //List(Alex)
  }

  def multiple(n:Int): Int = {
    println("multiple 被调用~~")
    2 * n}

  def stringTrans(s: String) : String ={
    s.toUpperCase()}

  def stringeql(s: String) : Boolean ={
    s.startsWith("A")
  }
}

化简 reduce - 二元函数引用于集合中的函数

object ReduceTest1 {
  def main(args: Array[String]): Unit = {

    //简化 求和
    //def reduceLeft[B >: A](op: (B, A) => B): B
    //reduceLeft(f) 接收的函数需要的形式为 op: (B, A) => B): B  理解为 传个函数(俩参数) 返回一个值(给left or right)
    //reduceleft(f) 的运行规则是 从左边开始执行将得到的结果返回给第一个参数 //步骤1 (1 + 2)
    // 再和下一个元素运行,继续返回给第一个参数   //步骤2 (1 + 2) + 3

    val list1 = List(1, 2, 3)
    val result = list1.reduceLeft(addSum)
    println(result)

    val list2 = List(10, 20, 30)
    println(list2.reduceLeft(mins))  // -40 (10-20) -30
    println(list2.reduceRight(mins)) // 20  10- (20-30)

    //最小值
    val list3 = List(100, 20, 30)
    println( list3.reduceLeft(minValue) )  //20
  }

  def addSum(i1: Int, i2: Int) :Int = {
    i1 + i2}

  def mins (j1: Int, j2: Int): Int ={
    j1 - j2}

  def minValue(x1: Int, x2: Int) : Int = {
    if (x1 > x2) x2 else  x1
  }
}


折叠 fold函数将上一步返回的值作为函数的第一个参数继续传递参与运算,直到list中的所有元素被遍历(相关函数 foldfoldLeftfoldRight

object FoldTest1 {
  def main(args: Array[String]): Unit = {
    val list1 = List(1, 2, 3, 4)

    // 函数的柯里化
    // 源码:
    //override def foldLeft[B](z: B)(op: (B, A) => B): B = {
    //    var acc = z ; var these: LinearSeq[A] = coll   //定义一个集合
    //    while (!these.isEmpty) {
    //      acc = op(acc, these.head)  //op(acc,集合第一个元素) 返回值-> acc
    //      these = these.tail    }      // 集合 为 these tail (出去head 剩余元素)
    //    acc   // 返回acc
    //  }
    //(20-1) -1  -> ((20-1) -1) -2 ....

    val result1 = list1.foldLeft(20)(mins)  //20
    println(result1)  //10

    val result2 = list1.foldRight(20)(mins)
    println(result2 ) //18   (4-20) -> 3-(4-20) #19-> 2 -19 #-17 -> 1-(-17) 18
    
  }
  def mins(i1: Int, i2: Int) :Int = {
    i1 - i2}
}


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

object ScanTest {
  def main(args: Array[String]): Unit = {

    //扫描,即对某个集合的所有元素做fold操作,但是会把产生的所有中间结果放置于一个集合中保存
    // (1 to 5) 遍历,先把 5 保留下来 (5, ) 然后再 开始fold(1,2,3,4,5) -> (5, 4, 2, -1, -5, -10)
    val result = (1 to 5).scanLeft(5)(minus) //IndexedSeq[Int]
    println("result=" + result) // 返回一个IndexSeq[] 索引序列

   // (  50) 右flod (1,2,3,4,5) -> ( 1-8 ,2-(-6) ,3-9 ,4-(-5) , -5, 10)
    var result_right = (1 to 5).scanRight(10)(minus)
    println(result_right)  //Vector(-7, 8, -6, 9, -5, 10)

  }

  def minus( num1 : Int, num2 : Int ) : Int = {
    num1 - num2
  }
}


扩展 Others
拉链 zip (对偶元组合并) 本质就是两个集合的合并操作,合并后每个元素是一组 对偶元组
迭代器  iterator 方法从集合获得一个迭代器 hasNext  next()

object OthersTest {
  def main(args: Array[String]): Unit = {
    //本质就是两个集合的合并操作,合并后每个元素是一组 对偶元组
    //两个集合个数不对应,会造成数据丢失  不限于List, 也可以是其它集合(Array)

    val list1 = List(1, 2, 3)
    val list2 = List(11, 22, 33)
    val list3 = list1.zip(list2) //List((1,11), (2,22), (3,33))
    println("list3=" + list3)

    //如果要取出合并后的各个对偶元组的数据,可以遍历
    for (item <- list3){
      println(item._1 + " - "+ item._2) //1 - 11
    }

    // 迭代器 通过iterator方法从集合获得一个迭代器
    val iterator = list1.iterator
    while (iterator.hasNext){
      println(iterator.next())
    }
    // 指针要重置下
    val iterator2 = list1.iterator
    for (ee <- iterator2) {
      println(ee)}
  }
}


stream是一个集合可以用于存放无穷多个元素
但是这无穷个元素并不会一次性生产出来,而是需要用到多大的区间,就会动态的生产,末尾元素遵循lazy规则

object StreamTest {
  def main(args: Array[String]): Unit = {
    def numsForm1(n: BigInt) : Stream[BigInt] = n #:: numsForm1(n + 1)
    def numsForm2(n: BigInt): LazyList[BigInt] = n #:: numsForm2(n + 1)

 //stream是一个集合。可以用于存放无穷多个元素,
 // 但是这无穷个元素并不会一次性生产出来,而是需要用到多大的区间,就会动态的生产,末尾元素遵循lazy规则
    val stream1 = numsForm1(10)
    println("head=" + stream1.head) //head=10
    println(stream1.tail)   //Stream(11, <not computed>)
    println(stream1) //Stream(10, 11, <not computed>)

    val stream2 = numsForm2(10)
    println("head=" + stream1.head)   //head=10
    println(stream2.tail)  //LazyList(<not computed>)
    println(stream2)   //LazyList(10, <not computed>)
  }
}


view方法产出一个总是被懒执行的集合。
view不会缓存数据,每次都要重新计算,比如遍历View

object ViewTest {
  def main(args: Array[String]): Unit = {
    val viewSquares1 = (1 to 50).filter(eq)
    println(viewSquares1)  //Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44)

    //使用view,来完成这个问题,程序中,对集合进行map,filter,reduce,fold...
    //你并不希望立即执行,而是在使用到结果才执行,则可以使用view来进行优化.
    val viewSquares2 = (1 to 30).view.filter(eq)
    println(viewSquares2)  //View(<not computed>) filter并未执行 待真正调用时候执行

    //eq 被调用.. 10 调用 未打印
    //eq 被调用.. 11 调用  打印出来
    //11
    for (item <- viewSquares2){    // 操作viewSquare2 时候 filter才会生效
      println(item)}
  }

  def multiple(num: Int): Int = {
    num}

  def eq(i: Int): Boolean ={
    println("eq 被调用..")
    i.toString.equals(i.toString.reverse)
  }

}

线程安全的集合
SynchronizedBuffer
SynchronizedMap
SynchronizedPriorityQueue
SynchronizedQueue
SynchronizedSet
SynchronizedStack

并行集合
Scala为了充分使用多核CPU,提供了并行集合
主要用到的算法有: 
Divide and conquer : 分治算法,Scala通过splitters(分解器),combiners(组合器)等抽象层来实现,
主要原理是将计算工作分解很多任务,分发给一些处理器去完成,并将它们处理结果合并返回Work stealin算法,
主要用于任务调度负载均衡(load-balancing)

object ParDemo01 {
  def main(args: Array[String]): Unit = {

    (1 to 5).foreach(println(_))
    println()
    //这里输出的结果是无序的,说明是将println任务分配给不同cpu
    (1 to 5).par.foreach(println(_))

   val result1 = (0 to 100).map{case _ => Thread.currentThread.getName}.distinct  // 始终是主线程
    val result2 = (0 to 100).par.map{case _ => Thread.currentThread.getName}.distinct // 不同线程
    
    println(result1) //非并行
    println("--------------------------------------------")
    println(result2) //并行
  }
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。