高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数。在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()
}
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:将符合要求的数据(筛选)放置到新的集合中
将 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")
}
}
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
}
}
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)) // 函数的柯里化
}
}
扫描,即对某个集合的所有元素做 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)
}
}
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
}
}
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))
}
}