Scala高阶函数之 map, reduce, flatMap(扁平化), fold(折叠), scan(扫描)

高阶函数:

高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数。在Scala中函数是“一等公民”,所以允许定义高阶函数。这里的术语可能有点让人困惑,我们约定,使用函数值作为参数,或者返回值为函数值的“函数”和“方法”,均称之为“高阶函数”。
最常见的一个例子是Scala集合类(collections)的高阶函数map

object HighOrderFunDemo02 {
     
  def main(args: Array[String]): Unit = {
     
    test2(sayOK)
  }

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

  private def sayOK() = {
     
    println("sayOKKK...")
  }

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

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

Map机制的模拟实现

object MapOperateDemo02 {
     
  def main(args: Array[String]): Unit = {
     
    /*
    请将 List(3,5,7) 中的所有元素都 * 2 , 将其结果放到一个新的集合中返回,
    即返回一个新的 List(6,10,14), 请编写程序实现.
    */
    val list = List(3, 5, 7, 9)
    //说明 list.map(multiple) 做了什么
    //1. 将 list 这个集合的元素 依次遍历
    //2. 将各个元素传递给 multiple 函数 => 新 Int
    //3. 将得到新 Int ,放入到一个新的集合并返回
    //4. 因此 multiple 函数调用 3
    val list2 = list.map(multiple)
    println("list2=" + list2) //List(6,10,14)
    //深刻理解 map 映射函数的机制-模拟实现
    val myList = MyList()
    val myList2 = myList.map(multiple)
    println("myList2=" + myList2)
  }

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

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

  //写 map
  def map(f: Int => Int): List[Int] = {
     
    //遍历集合
    for (item <- this.list1) {
     
      //过滤,扁平化。。。
      list2 = list2 :+ f(item)
    }
    list2
  }
}

object MyList {
     
  def apply(): MyList = new MyList()
}
flatmap 扁平化映射:

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

object FlatMapDemo01 {
     
  def main(args: Array[String]): Unit = {
     
    val names = List("Alice", "Bob", "Nick")
    //需求是将 List 集合中的所有元素,进行扁平化操作,即把所有元素打散
    val names2 = names.flatMap(upper)
    println("names2=" + names2)
  }
  def upper(s: String): String = {
     
    s.toUpperCase
  }
}
filter 集合元素的过滤:

基本的说明 filter:将符合要求的数据(筛选)放置到新的集合中
将 val names = List(“Alice”, “Bob”, “Nick”) 集合中首字母为’A’的筛选到新的集合。

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

化简:

reduceLeft(reduce)
object ReduceDemo01 {
     
  def main(args: Array[String]): Unit = {
     
    /*
    使用化简的方式来计算 list 集合的和
    */
    val list = List(1, 20, 30, 4, 5)
    val res = list.reduceLeft(sum) // reduce/reduceLeft/reduceRight
    //执行的流程分析
    //步骤 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 = {
     
      println("sum 被调用~~")
      n1 + n2
    }
  }
}

利用reduce求出List(3,4,2,7,5)的最小值

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

    def minus(num1: Int, num2: Int): Int = {
     
      num1 - num2
    }
    // (((1-2) - 3) - 4) - 5 = -13
    println(list.reduceLeft(minus))
    // 输出? -13
    // 1 - (2 - (3 -(4 - 5))) = 3
    println(list.reduceRight(minus)) //输出? 3
    // reduce 等价于 reduceLeft
    println(list.reduce(minus))
    println("smallest=" + list.reduceLeft(min)) // 1
  }

  // 求出最小值
  def min(n1: Int, n2: Int): Int = {
     
    if (n1 > n2) n2 else n1
  }
}
fold 折叠
  1. fold函数将上一步返回的值作为函数的第一个参数继续传递参与运算,直到list中的所有元素被遍 历。
  2. 可以把 reduceLeft 看做简化版的 foldLeft。
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 就是调用的 foldLeftB,并且是默认从集合的 head 元素开始操作的。

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

    def minus(num1: Int, num2: Int): Int = {
     
      num1 - num2
    }
    //说明
    //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)) // 函数的柯里化
  }
}
Scan 扫描

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

object ScanDemo01 {
     
  def main(args: Array[String]): Unit = {
     
    //普通函数
    def minus(num1: Int, num2: Int): Int = {
     
      num1 - num2
    }

    //5 (1,2,3,4,5) =>(5, 4, 2, -1, -5, -10)
    //Vector(5, 4, 2, -1, -5, -10)
    val i8 = (1 to 5).scanLeft(5)(minus) //IndexedSeq[Int]
    println("i8=" + i8)

    //普通函数
    def add(num1: Int, num2: Int): Int = {
     
      num1 + num2
    }

    //(1,2,3,4,5) 5 => (20,19,17,14, 10,5)
    val i9 = (1 to 5).scanRight(5)(add) //IndexedSeq[Int]
    println("i9=" + i9)
  }
}

练习

  1. val sentence = “AAAAAAAAAABBBBBBBBCCCCCDDDDDDD”
    将 sentence 中各个字符,通过 foldLeft 存放到 一个 ArrayBuffer 中
import scala.collection.mutable.ArrayBuffer

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
  }
}
  1. val sentence = “AAAAAAAAAABBBBBBBBCCCCCDDDDDDD”
    使用映射集合,统计一句话中,各个字母出现的次数
import scala.collection.mutable

object Exercise03 {
     
  def main(args: Array[String]): Unit = {
     
    val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD"
    val map2 = sentence.foldLeft(Map[Char, Int]())(charCount)
    println("map2=" + map2)
    //使用可变的 map,效率更高.
    //1. 先创建一个可变 map,作为左折叠的第一个参数
    val map3 = mutable.Map[Char, Int]()
    sentence.foldLeft(map3)(charCount2)
    println("map3=" + map3)
  }

  //使用不可变 map 实现
  def charCount(map: Map[Char, Int], char: Char): Map[Char, Int] = {
     
    map + (char -> (map.getOrElse(char, 0) + 1))
  }

  //使用可变 map 实现
  def charCount2(map: mutable.Map[Char, Int], char: Char): mutable.Map[Char, Int] = {
     
    map += (char -> (map.getOrElse(char, 0) + 1))
  }
}

你可能感兴趣的:(Scala,Scala,高阶函数)