Фильтрация
Фильтрация — одна из самых популярных задач при обработке коллекций. В 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.toUpperCase())
}
//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) // 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–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/collection-filtering.html