Kotlin的函数式编程特性为集合数据处理提供了很多便捷方法,其中多条件谓词处理和相邻元素访问是实际开发中经常遇到的场景,掌握对应的实现方式可以大幅提升代码的简洁性和可读性。

多条件谓词的处理方式
谓词指的是返回布尔值的判断逻辑,在Kotlin中常用filter、any、all等函数式方法接收谓词参数。当需要处理多个判断条件时,有以下几种常见实现方式。
使用逻辑运算符组合条件
最直接的方式是在谓词lambda中使用逻辑与&&、逻辑或||运算符组合多个条件,这种方式适合条件数量较少的场景。
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 筛选大于3且小于8的偶数
val result = numbers.filter { it > 3 && it < 8 && it % 2 == 0 }
println(result) // 输出 [4, 6]
}
提取谓词为独立函数
当条件逻辑比较复杂或者需要复用时,可以将单个条件提取为独立的谓词函数,再通过逻辑运算符组合,提升代码的可维护性。
fun isGreaterThanThree(num: Int): Boolean = num > 3
fun isLessThanEight(num: Int): Boolean = num < 8
fun isEven(num: Int): Boolean = num % 2 == 0
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 组合多个独立谓词
val result = numbers.filter { isGreaterThanThree(it) && isLessThanEight(it) && isEven(it) }
println(result) // 输出 [4, 6]
}
使用谓词扩展函数组合
Kotlin中可以为Predicate类型添加扩展函数,实现谓词的灵活组合,这种方式适合需要动态组合多个条件的场景。
// 定义谓词类型别名
typealias Predicate<T> = (T) -> Boolean
// 与运算扩展函数
infix fun <T> Predicate<T>.and(other: Predicate<T>): Predicate<T> = { this(it) && other(it) }
// 或运算扩展函数
infix fun <T> Predicate<T>.or(other: Predicate<T>): Predicate<T> = { this(it) || other(it) }
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 定义单个谓词
val greaterThanThree: Predicate<Int> = { it > 3 }
val lessThanEight: Predicate<Int> = { it < 8 }
val even: Predicate<Int> = { it % 2 == 0 }
// 组合谓词
val combinedPredicate = greaterThanThree and lessThanEight and even
val result = numbers.filter(combinedPredicate)
println(result) // 输出 [4, 6]
}
相邻元素的访问方式
在处理集合数据时,经常需要访问当前元素和相邻的前一个或后一个元素,Kotlin提供了多种实现方式。
使用索引遍历
通过withIndex或者indices获取元素索引,再通过索引访问相邻元素,需要注意边界判断避免索引越界。
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// 遍历元素,同时访问前一个元素
for ((index, value) in numbers.withIndex()) {
val prev = if (index > 0) numbers[index - 1] else null
println("当前元素: $value, 前一个元素: $prev")
}
// 输出:
// 当前元素: 1, 前一个元素: null
// 当前元素: 2, 前一个元素: 1
// 当前元素: 3, 前一个元素: 2
// 当前元素: 4, 前一个元素: 3
// 当前元素: 5, 前一个元素: 4
}
使用windowed函数
windowed是Kotlin集合的扩展函数,它可以生成滑动窗口,每个窗口包含指定数量的相邻元素,非常适合处理相邻元素访问的场景。
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// 窗口大小为2,步长为1,不部分窗口
val windows = numbers.windowed(2, 1, false)
windows.forEach { window ->
println("相邻元素对: ${window[0]}, ${window[1]}")
}
// 输出:
// 相邻元素对: 1, 2
// 相邻元素对: 2, 3
// 相邻元素对: 3, 4
// 相邻元素对: 4, 5
// 计算相邻元素的和
val sumOfAdjacent = numbers.windowed(2, 1, false).map { it[0] + it[1] }
println(sumOfAdjacent) // 输出 [3, 5, 7, 9]
}
使用zipWithNext函数
zipWithNext是更简洁的相邻元素处理函数,它会将集合中相邻的元素两两配对,返回一个包含相邻元素对的列表,内部已经做了边界处理。
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// 直接获取相邻元素对
val adjacentPairs = numbers.zipWithNext()
adjacentPairs.forEach { (a, b) ->
println("相邻元素: $a, $b")
}
// 输出:
// 相邻元素: 1, 2
// 相邻元素: 2, 3
// 相邻元素: 3, 4
// 相邻元素: 4, 5
// 判断相邻元素是否递增
val isIncreasing = numbers.zipWithNext().all { (a, b) -> a < b }
println(isIncreasing) // 输出 true
}
实际场景示例
下面通过一个实际场景演示多条件谓词和相邻元素访问的组合使用,需求是筛选列表中数值在10到20之间、且后一个元素比当前元素大2的所有元素。
fun main() {
val data = listOf(8, 12, 14, 17, 19, 22, 25)
// 多条件谓词:数值在10到20之间
val rangePredicate: Predicate<Int> = { it >= 10 && it <= 20 }
// 相邻元素判断:后一个元素比当前元素大2
val result = data.zipWithNext()
.filter { (current, next) -> rangePredicate(current) && next - current == 2 }
.map { it.first }
println(result) // 输出 [12, 17]
}
通过上述方法,开发者可以根据不同的场景选择合适的多条件谓词组合方式和相邻元素访问方式,让Kotlin函数式代码更加简洁高效。