kotlin学习之高阶函数及常用基本高阶函数

Posted mictoy_朱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kotlin学习之高阶函数及常用基本高阶函数相关的知识,希望对你有一定的参考价值。

基本概念 f(g(x))

与普通函数不一样,高阶函数是传入或者返回函数的函数,例如,我们可能用到的forEach就是一个高阶函数
示例代码:

fun main() 
    val myOperate = AdvanceOperate()    //定义实例
    val operate1 = myOperate.multipleOperate(2,3)      //高阶函数调用
        num1, num2 -> "plus operate:$num1 + $num2 = $num1+num2"
    
    println(operate1)
    val operate2 = myOperate.multipleOperate(2,3)
            num1, num2 ->
        "chengfa operate:$num1 * $num2 = $num1*num2"     //定义成两个数的积
    
    println(operate2)



class AdvanceOperate
    //定义高阶函数
    fun multipleOperate(num1:Int,num2:Int,operate:(num1:Int,num2:Int)->String):String//第三个参数为普通函数
        println("$num1 and $num2 for different operate")
        return operate(num1,num2)
    

运行结果:

2 and 3 for different operate
plus operate:2 + 3 = 5
2 and 3 for different operate
chengfa operate:2 * 3 = 6

常见高阶函数

map/flatMap

  • map:数组映射
    val strs:Array<String> = arrayOf("Hello","USA","England","China")   //定义一个字符串数组
    strs.forEach (::println)    //通过forEach打印(这里forEach也是一个高阶函数,println是包级函数)
    println("-----------------------")
    val newStrs = strs.map  "$it length is $it.length"      //通过高阶函数map映射功能生成一个新list
    newStrs.forEach(::println)

运行打印结果:

Hello
USA
England
China
-----------------------
Hello length is 5
USA length is 3
England length is 7
China length is 5

map源码:

/**
 * Returns a list containing the results of applying the given [transform] function
 * to each element in the original array.
 */
public inline fun <T, R> Array<out T>.map(transform: (T) -> R): List<R> 
    return mapTo(ArrayList<R>(size), transform)

源码解读:

描述:可以看出他是Array的一个扩展函数,返回一个通过[transform]函数对原始数组中的元素进行一一映射后生成的新list
参数transform是一个参数为T并返回R的函数
返回值类型是List

另外,可以看下forEach的源码:

/**
 * Performs the given [action] on each element.
 */
public inline fun <T> Array<out T>.forEach(action: (T) -> Unit): Unit 
    for (element in this) action(element)   //通过for循环对Array里的元素以action方法进行处理

源码解读:

forEach函数也是Array中的一个扩展函数,而action可以为任意同以element为参数的函数

  • flatMap:平铺元素为数组的数组

flat:n 平面,面,片,住宅,套件;adj 平坦的,平的,扁

示例代码

    val list = listOf(
        1..3,
        2..5,
        1..6,
    )
    val flatList = list.flatMap  it 
    flatList.forEach
        print("$it,")
    

运行结果:

1,2,3,2,3,4,5,1,2,3,4,5,6,

flatMap源码解读

/**
 * Returns a single list of all elements yielded from results of [transform] function being invoked on each element of original collection.
 */
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> 
    return flatMapTo(ArrayList<R>(), transform)

//可以看到,与map不一样的是flatMap的作为参数的函数[transform]返回的不是单纯的数据R而是一个R的集合[Iterable],而flatMap本身的返回值同map一样是一个List<R>
//再看flatMapTo方法:
/**
 * Appends all elements yielded from results of [transform] function being invoked on each element of original collection, to the given [destination].
 */
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C 
    for (element in this)      //这里通过for循环以及下面我们熟悉的addAll方法可以知道原始数组的数据就这样添加到了新的List中
        val list = transform(element)
        destination.addAll(list)
    
    return destination

当然,我们也可以对进行稍微复杂的操作,比如对最终返回List的元素进行乘方在添加“Num.”

val flatList2 = list.flatMap  intRange ->
        intRange.map   //注意,这里要区分intRange和it,从上面的源码我们知道IntRange是一个数组,所以需要用map方法映射元素最终形式
            "Num.$it*it"
        
    
    flatList2.forEach
        print("$it ")
    

运行结果:

Num.1 Num.4 Num.9 Num.4 Num.9 Num.16 Num.25 Num.1 Num.4 Num.9 Num.16 Num.25 Num.36

fold/reduce

  • reduce:对数组通过特定方法进行累计计算,初始值为数组第一个值

reduce:vi 减少,降低,缩小,压缩,简化,裁剪
def:make smaller or less in account,degree,or size

reduce方法源码:

/**
 * Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element.
 * 从第一个元素开始累积值,并从左到右应用[operation]到当前累加器值和每个元素。(谷歌翻译)
 */
public inline fun <S, T : S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S 
    val iterator = this.iterator()
    if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
    var accumulator: S = iterator.next()
    while (iterator.hasNext()) 
        accumulator = operation(accumulator, iterator.next()) //累计过程,通过operation方法,计算相关结果 
    
    return accumulator

由上可知,我们可以用该方法实现一个累加、累乘等功能,比如,实现一个数列的累加,累乘:

    val sum_he = flatList.reduce  acc, num -> acc + num 
    println("sum = $sum_he")
    println("-----------------------")
    val sum_ji = flatList.reduce  acc, num -> acc * num 
    println("sum = $sum_ji")

运行结果:

sum = 41
----------------------
sum = 518400

  • fold:对数组通过特定方法进行累计计算,初始值通过调用方法指定

fold:vi 折,折叠,合拢,抱住;n 合拢,圈

fold方法源码:

/**
 * Accumulates(累计,累加) value starting with [initial] value and applying [operation] from left to right to current accumulator value and each element.
 * 累计以[initial]值开始并从左到右应用[operation]到当前累加器值和每个元素的值。(谷歌翻译)
 */
public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R 
    var accumulator = initial
    for (element in this) accumulator = operation(accumulator, element)
    return accumulator

通过源码可知,fold与reduce方法功能基本一致,唯一不一样的地方是fold多了一个指定初始值参数[initial],而reduce方法是没有这个参数的,同样可以通过示例代码理解fold方法:

	val sum = flatList.fold(10)
            acc, i -> acc+i
    
    println("sum = $sum")

运行结果:

sum = 51

filter/takeWhile

  • filter:通过特定方法(规则),过滤某些元素,返回一个新的list集合

filter:vi 过滤,筛选;adj 过滤器,滤波器

filter方法源码:

/**
 * Returns a list containing only elements matching the given [predicate].
 * 返回仅包含与给定[predicate]匹配的元素的列表。(谷歌翻译)
 */
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> 
    return filterTo(ArrayList<T>(), predicate)

很明显这是一个过滤器方法,通过[predicate]方法过滤掉不符合规则的元素,返回一个新的list
由此,我们可以编写示例方法,比如,我们要筛选出列表中的偶数

val evenList = flatList.filter 
        it%2 == 0

evenList.forEachprint("$it,")

运行结果

2,2,4,2,4,6,

  • takeWhile:

takeWhile:v 拿走

takeWhile方法源码:

/**
 * Returns a list containing first elements satisfying the given [predicate].
 * 返回包含满足给定方法[predicate]的第一个元素的列表。(谷歌翻译)
 * @sample samples.collections.Collections.Transformations.take
 */
public inline fun <T> Iterable<T>.takeWhile(predicate: (T) -> Boolean): List<T> 
    val list = ArrayList<T>()
    for (item in this) 
        if (!predicate(item))
            break
        list.add(item)
    
    return list

很明显,它返回的是一个元素满足[predicate]方法的list,循环获取集合中的元素,一旦发现某个元素不符合该规则,程序立马跳出循环,返回一个新list
写一个item != 5 的方法调用。ps:不知道该方法有何可用之地

val takeWhile = flatList.takeWhile 
        it != 5

takeWhile.forEachprint("$it,")

运行结果:

1,2,3,2,3,4,

let/apply/with/use
这几个函数都是为了简洁化代码而设计的,篇幅原因,这里不做详解(懒!!!)

以上是关于kotlin学习之高阶函数及常用基本高阶函数的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin的高阶函数和常用高阶函数

11Kotlin项目实操之高阶函数二

09Kotlin项目实操之高阶函数一

11Kotlin项目实操之高阶函数二

09Kotlin项目实操之高阶函数一

Python学习之高阶函数——map/reduce