Фильтрация коллекций
Фильтрация — одна из самых популярных задач при обработке коллекций. В Kotlin условия фильтрации определяются предикатами — лямбда-функциями, которые принимают элемент коллекции и возвращают булево значение: 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()возвращает все ненулевые элементы. При вызове наList<T?>,filterNotNull()возвращаетList<T: Any>, позволяя рассматривать элементы как объекты, не имеющие значение null.fun main() { //sampleStart val numbers = listOf(null, "one", "two", null) numbers.filterNotNull().forEach { println(it.length) // length is unavailable for nullable Strings } //sampleEnd }
Разделение
Ещё одна функция фильтрации — partition() — фильтрует коллекцию по предикату и сохраняет элементы, которые ему не соответствуют, в отдельном списке. Таким образом, на выходе получается 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
}
Проверка предикатов
Наконец, существуют функции, которые просто проверяют предикат на элементах коллекции:
any()возвращаетtrueесли хотя бы один элемент соответствует данному предикату.none()возвращаетtrueесли ни один из элементов не соответствует данному предикату.all()возвращаетtrueесли все элементы соответствуют данному предикату. Обратите внимание, чтоall()возвращаетtrueпри вызове с любым корректным предикатом на пустой коллекции. Такое поведение известно в логике как пустая истинность.
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
}
© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/collection-filtering.html