Kotlin中函数式编程API(3)✔️三大基础函数
- filter
- map
- reduce
过滤、映射 和 聚合 是数据的三大基本操作,围绕这三大基础操作会有很多函数,但其中有三个函数是作为基础的函数:filter、map 和 reduce。
一、filter
过滤操作使用filter
函数,它可以对Collection
集合、Map
集合 或 数组
元素进行过滤,Collection 集合 和 数组 返回的是一个 List集合,Map 集合返回的还是一个 Map 集合。
class Person(val name: String, val age: Int) {
override fun toString(): String = "[$name, $age]"
}
val people = listOf(
Person("Tony star", 3),
Person("Lawrence Li", 3), Person("tom Chen", 3),
Person("Alex", 3), Person("Xiao san", 3)
)
val peopleMap = mapOf(
"a" to Person("Tony star", 3),
"b" to Person("Lawrence Li", 3), "bf" to Person("tom Chen", 3),
"af" to Person("Alex", 3), "sex" to Person("Xiao san", 3)
)
fun main(args: Array<String>?) {
people.filter {
it.name.startsWith("t", ignoreCase = true)
}.forEach {
println("{name=${it.name}, age=${it.age}}")
}
peopleMap.filter {
it.key.startsWith("a") &&
it.value.name.startsWith("a", ignoreCase = true)
}.forEach { println("(${it.key}, ${it.value.toString()})") }
}
// 输出结果
2019-06-13 15:17:48.706 I: {name=Tony star, age=3}
2019-06-13 15:17:48.707 I: {name=tom Chen, age=3}
2019-06-13 15:17:48.710 I: (af, [Alex, 3])
filter
函数中的 Lambda 表达式返回布尔值,true
的元素进入下一个函数,false
的元素被过滤掉,表达式it.name.startsWith("t", ignoreCase = true)
是判断集合元素的name
属性是否为 t 字母开头,ignoreCase = true
忽略大小写进行比较。
二、map
映射操作使用 map 函数,它可以对 Collection 集合、Map 集合 或 数组 元素进行变换并 返回一个List 集合。
fun main(args: Array<String>?) {
people.map { it.name }.forEach { println(it) }
peopleMap.map { it.value }.filter { it.name.startsWith("T") }
.forEach { println(it) }
}
// 输出结果
2019-06-13 15:38:40.567 I: Tony star
2019-06-13 15:38:40.567 I: Lawrence Li
2019-06-13 15:38:40.567 I: tom Chen
2019-06-13 15:38:40.567 I: Alex
2019-06-13 15:38:40.567 I: Xiao san
2019-06-13 15:38:40.573 I: [Tony star, 3]
Map 函数对集合进行变换,it.name
是变换表达式,将计算的结果放到一个新的 List 集合中。
三、reduce
聚合操作会将 Collection
集合 或 数组
中的数据聚合起来输出单个数据,聚合操作中最基础的是归纳函数 reduce
,reduce
函数会将 集合
或 数组
的元素按照指定的算法积累叠加起来,最后输出一个数据。
- 分析
reduce
源码
// reduce的kotlin源码
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())
}
return accumulator
}
源码分析:1、从源码看 reduce
是迭代器的 Iterable
的扩展函数。2、从方法体第一行代码 val iterator = this.iterator()
分析凡是对象内含有 iterator()
函数并且返回值为 Iterator<T>
类型都可以调用 reduce
扩展函数。3、函数体内定义了局部变量 accumulator
存放返回值,初始值为迭代器的第一个存储值,当迭代器中存储值大于2个时,调用 operation
表达式运算,注意 operation
第一次调用时参数为 accumulator
,即迭代器第一个存储值。
-
reduce
使用案例
class Student(val name: String, val score: Int) {
override fun toString(): String = "[$name, $score]"
}
val students = setOf(
Student("Tony star", 64), Student("小三", 99),
Student("Lawrence Li", 78), Student("tom Chen", 86),
Student("Alex", 25), Student("小五", 95)
)
fun main(args: Array<String>?) {
val total = students.map { it.score }.reduce { total, score -> total + score }
println("total score is $total")
}
// 输出结果
2019-06-13 15:59:00.153 I: total score is 447
调用 reduce 函数计算分数,其中 total 参数是上次积累的计算结果,score 为当前元素,total + score
表达式是进行累加。