Spec-Zone.ru › Kotlin 1.8

Фильтрация коллекций

Фильтрация — одна из самых популярных задач при обработке коллекций. В 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
}
Последнее изменение: 10 января 2023
Операции преобразования коллекций Операторы плюс и минус

© 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API