集合聚合操作
Kotlin 集合包含用于常用的 聚合操作 (基于集合内容返回单个值的操作)的函数 。 其中大多数是众所周知的,并且其工作方式与在其他语言中相同。
fun main() {
//sampleStart
val numbers = listOf(6, 42, 10, 4)
println("Count: ${numbers.count()}")
println("Max: ${numbers.max()}")
println("Min: ${numbers.min()}")
println("Average: ${numbers.average()}")
println("Sum: ${numbers.sum()}")
//sampleEnd
}
还有一些通过某些选择器函数或自定义 Comparator
来检索最小和最大元素的函数。
maxBy()
/minBy()
接受一个选择器函数并返回使选择器返回最大或最小值的元素。maxWith()
/minWith()
接受一个Comparator
对象并且根据此Comparator
对象返回最大或最小元素。
fun main() {
//sampleStart
val numbers = listOf(5, 42, 10, 4)
val min3Remainder = numbers.minBy { it % 3 }
println(min3Remainder)
val strings = listOf("one", "two", "three", "four")
val longestString = strings.maxWith(compareBy { it.length })
println(longestString)
//sampleEnd
}
此外,有一些高级的求和函数,它们接受一个函数并返回对所有元素调用此函数的返回值的总和:
sumBy()
使用对集合元素调用返回Int
值的函数。sumByDouble()
与返回Double
的函数一起使用。
fun main() {
//sampleStart
val numbers = listOf(5, 42, 10, 4)
println(numbers.sumBy { it * 2 })
println(numbers.sumByDouble { it.toDouble() / 2 })
//sampleEnd
}
Fold 与 reduce
对于更特定的情况,有函数 reduce()
和 fold()
,它们依次将所提供的操作应用于集合元素并返回累积的结果。
操作有两个参数:先前的累积值和集合元素。
这两个函数的区别在于:fold()
接受一个初始值并将其用作第一步的累积值,而 reduce()
的第一步则将第一个和第二个元素作为第一步的操作参数。
fun main() {
//sampleStart
val numbers = listOf(5, 2, 10, 4)
val sum = numbers.reduce { sum, element -> sum + element }
println(sum)
val sumDoubled = numbers.fold(0) { sum, element -> sum + element * 2 }
println(sumDoubled)
//val sumDoubledReduce = numbers.reduce { sum, element -> sum + element * 2 } //错误:第一个元素在结果中没有加倍
//println(sumDoubledReduce)
//sampleEnd
}
上面的实例展示了区别:fold()
用于计算加倍的元素之和。
如果将相同的函数传给 reduce()
,那么它会返回另一个结果,因为在第一步中它将列表的第一个和第二个元素作为参数,所以第一个元素不会被加倍。
如需将函数以相反的顺序应用于元素,可以使用函数 reduceRight()
和 foldRight()
它们的工作方式类似于 fold()
和 reduce()
,但从最后一个元素开始,然后再继续到前一个元素。
记住,在使用 foldRight 或 reduceRight 时,操作参数会更改其顺序:第一个参数变为元素,然后第二个参数变为累积值。
fun main() {
//sampleStart
val numbers = listOf(5, 2, 10, 4)
val sumDoubledRight = numbers.foldRight(0) { element, sum -> sum + element * 2 }
println(sumDoubledRight)
//sampleEnd
}
你还可以使用将元素索引作为参数的操作。
为此,使用函数 reduceIndexed()
和 foldIndexed()
传递元素索引作为操作的第一个参数。
最后,还有将这些操作从右到左应用于集合元素的函数——reduceRightIndexed()
与 foldRightIndexed()
。
fun main() {
//sampleStart
val numbers = listOf(5, 2, 10, 4)
val sumEven = numbers.foldIndexed(0) { idx, sum, element -> if (idx % 2 == 0) sum + element else sum }
println(sumEven)
val sumEvenRight = numbers.foldRightIndexed(0) { idx, element, sum -> if (idx % 2 == 0) sum + element else sum }
println(sumEvenRight)
//sampleEnd
}
All reduce operations throw an exception on empty collections. To receive null
instead, use their *OrNull()
counterparts: