본문으로 건너뛰기

컬렉션 필터링

필터링은 컬렉션 처리에서 가장 많이 사용되는 작업 중 하나입니다. Kotlin에서 필터링 조건은 predicate (컬렉션 요소를 가져와 부울 값을 반환하는 람다 함수)로 정의됩니다. true는 주어진 요소가 predicate와 일치함을 의미하고 false는 그 반대를 의미합니다.

표준 라이브러리에는 한 번의 호출로 컬렉션을 필터링할 수 있는 확장 함수 그룹이 포함되어 있습니다. 이러한 함수는 원래 컬렉션을 변경하지 않으므로 mutable 및 read-only 컬렉션 모두에 사용할 수 있습니다. 필터링 결과를 사용하려면 변수에 할당하거나 필터링 후 함수를 연결해야 합니다.

Predicate로 필터링

기본 필터링 함수는 filter()입니다. filter()는 predicate와 함께 호출될 때 일치하는 컬렉션 요소를 반환합니다. ListSet의 경우 결과 컬렉션은 List이고, Map의 경우 Map입니다.

fun main() {

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)

}

filter()의 predicate는 요소의 값만 확인할 수 있습니다. 필터에서 요소 위치를 사용하려면 filterIndexed()를 사용하세요. 이 함수는 인덱스와 요소 값의 두 가지 인수를 가진 predicate를 사용합니다.

부정 조건으로 컬렉션을 필터링하려면 filterNot()을 사용하세요. 이 함수는 predicate가 false를 생성하는 요소 목록을 반환합니다.

fun main() {

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)

}

지정된 유형의 요소를 필터링하여 요소 유형을 좁히는 함수도 있습니다.

  • filterIsInstance()는 지정된 유형의 컬렉션 요소를 반환합니다. List<Any>에서 호출되는 filterIsInstance<T>()List<T>를 반환하므로 해당 항목에서 T 유형의 함수를 호출할 수 있습니다.

    fun main() {

    val numbers = listOf(null, 1, "two", 3.0, "four")
    println("All String elements in upper case:")
    numbers.filterIsInstance<String>().forEach {
    println(it.uppercase())
    }

    }
  • filterNotNull()은 모든 null이 아닌 요소를 반환합니다. List<T?>에서 호출되는 filterNotNull()List<T: Any>를 반환하므로 요소를 null이 불가능한 객체로 처리할 수 있습니다.

    fun main() {

    val numbers = listOf(null, "one", "two", null)
    numbers.filterNotNull().forEach {
    println(it.length) // length is unavailable for nullable Strings
    }

    }

Partition

또 다른 필터링 함수인 partition()은 predicate로 컬렉션을 필터링하고 일치하지 않는 요소를 별도의 목록에 보관합니다. 따라서 ListPair를 반환 값으로 사용합니다. 첫 번째 목록에는 predicate와 일치하는 요소가 포함되고 두 번째 목록에는 원래 컬렉션의 나머지 모든 요소가 포함됩니다.

fun main() {

val numbers = listOf("one", "two", "three", "four")
val (match, rest) = numbers.partition { it.length > 3 }

println(match)
println(rest)

}

Predicate 테스트

마지막으로 컬렉션 요소에 대해 predicate를 간단히 테스트하는 함수가 있습니다.

  • any()는 하나 이상의 요소가 주어진 predicate와 일치하면 true를 반환합니다.
  • none()는 요소가 predicate와 일치하지 않으면 true를 반환합니다.
  • all()는 모든 요소가 주어진 predicate와 일치하면 true를 반환합니다. all()은 비어 있는 컬렉션에서 유효한 predicate와 함께 호출될 때 true를 반환합니다. 이러한 동작은 논리에서 _vacuous truth_로 알려져 있습니다.
fun main() {

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

}

any()none()은 predicate 없이도 사용할 수 있습니다. 이 경우 컬렉션이 비어 있는지 확인하기만 합니다. any()는 요소가 있으면 true를 반환하고 없으면 false를 반환합니다. none()은 그 반대를 수행합니다.

fun main() {

val numbers = listOf("one", "two", "three", "four")
val empty = emptyList<String>()

println(numbers.any())
println(empty.any())

println(numbers.none())
println(empty.none())

}