过滤(Filtering)集合
最终更新: 2024/03/21
在对集合的处理中, 过滤是最常见的任务之一.
Kotlin 中, 过滤条件使用 判定条件(predicate) 来表示 –
它是一个 lambda 函数, 接受的参数是集合元素, 返回结果是布尔值:
true
代表这个元素满足判定条件, false
表示不满足判定条件.
标准库提供了一组扩展函数, 你可以只通过一次函数调用就能过滤集合. 这些函数不修改原来的集合, 因此对 可变集合和只读集合 都可以使用. 要操作过滤后的结果集合, 你应该将它赋值给一个变量, 或者在过滤之后链式调用其他函数.
使用判定条件进行过滤
最基本的过滤函数是
filter()
.
调用这个函数时使用判定条件作为参数, filter()
函数会返回集合中满足这个判定条件的元素.
对于 List
和 Set
, 结果集合都是 List
, 对于 Map
, 结果集合也是 Map
.
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
val longerThan3 = numbers.filter { it.length > 3 }
println(longerThan3)
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10}
println(filteredMap)
//sampleEnd
}
在 filter()
函数的判定条件中, 只能检查元素的值.
如果在过滤时还想使用元素的位置, 请使用
filterIndexed()
函数.
这个函数的判定条件接受两个参数: 第一个是元素下标, 第二个是元素值.
如果要按照相反的条件来过滤集合, 请使用
filterNot()
函数.
它返回判定条件结果为 false
的元素.
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
val filteredIdx = numbers.filterIndexed { index, s -> (index != 0) && (s.length < 5) }
val filteredNot = numbers.filterNot { it.length <= 3 }
println(filteredIdx)
println(filteredNot)
//sampleEnd
}
还有一些函数, 可以根据元素的类型进行过滤, 得到元素类型缩窄后的集合:
-
filterIsInstance()
函数返回指定类型的集合元素. 对List<Any>
调用这个函数时,filterIsInstance<T>()
返回的结果集合类型为List<T>
, 因此你可以对结果集合的元素调用类型T
的函数.fun main() { //sampleStart val numbers = listOf(null, 1, "two", 3.0, "four") println("All String elements in upper case:") numbers.filterIsInstance<String>().forEach { println(it.uppercase()) } //sampleEnd }
-
filterNotNull()
函数返回不为 null 的元素. 对List<T?>
调用这个函数时,filterNotNull()
返回的结果集合类型为List<T: Any>
, 因此你可以将结果集合的元素作为不为 null 的对象进行处理.fun main() { //sampleStart val numbers = listOf(null, "one", "two", null) numbers.filterNotNull().forEach { println(it.length) // 对于可为 null 的 String, length 属性是不可访问的 } //sampleEnd }
划分(Partition)
另一个过滤函数 –
partition()
– 根据一个判定条件过滤集合, 并把不满足判定条件的元素保存到另一个 list 中.
因此从返回值可以得到两个 List
构成的 Pair
: 第一个 list 包含满足判定条件的元素, 第二个包含原集合中的所有其他元素.
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
val (match, rest) = numbers.partition { it.length > 3 }
println(match)
println(rest)
//sampleEnd
}
验证判定条件
最后, 还有一些函数用来对集合验证某个判定条件:
- (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/any.html)
函数, 如果至少存在一个元素满足指定的判定条件, 则返回
true
. none()
函数, 如果不存在任何元素满足指定的判定条件, 则返回true
.all()
函数, 如果所有的元素全部满足指定的判定条件, 则返回true
. 注意, 如果对空集合使用任何合法的判定条件调用all()
, 会返回true
. 这个结果在逻辑学上叫做 虚空真(vacuous truth).
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
println(numbers.any { it.endsWith("e") })
println(numbers.none { it.endsWith("a") })
println(numbers.all { it.endsWith("e") })
println(emptyList<Int>().all { it > 5 }) // vacuous truth
//sampleEnd
}
any()
和 none()
函数也可以不指定判定条件: 这种情况下它们只检查集合是否为空.
如果集合中存在元素, 则 any()
返回 true
, 集合中没有元素, 则 false
; none()
的返回值刚好与此相反.
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
val empty = emptyList<String>()
println(numbers.any())
println(empty.any())
println(numbers.none())
println(empty.none())
//sampleEnd
}