조용한 담장

코틀린(Kotlin) Collections : Filtering 본문

kotlin

코틀린(Kotlin) Collections : Filtering

iosroid 2020. 3. 24. 16:40

kotlin

코틀린의 collection 의 transformation 에 대해 살펴보자.

원문 https://kotlinlang.org/docs/reference/collection-filtering.html 을 보며 정리.

 

필터링은 전달된 람다함수가 collection 의 element 을 가지고 도출한 boolean 결과값이 true 이면 해당 element 값을 사용하고 false 이면 버린다.

standard library 는 filtering 을 위한 많은 확장 함수들을 하나의 호출을 통해 사용될수 있도록 제공한다.

이 함수들은 원본 collection 을 변경시키지 않고 보존하므로 mutable 과 read-only collection 모두에 사용이 가능하다.

filtering 의 결과는 변수에 저장하거나 filtering 이후 함수들의 chaining 을 통해 사용해야 한다.

Filtering by predicate

filter() 함수를 사용한다.

inline fun <T> Iterable<T>.filter(
   predicate: (T) -> Boolean
): List<T>
inline fun <K, V> Map<out K, V>.filter(
   predicate: (Entry<K, V>) -> Boolean
): Map<K, V>

ListSetList 를 결과로, MapMap 으로 결과를 리턴한다.

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)

// output:
// [three, four]
// {key11=11}

filterIndexed() 를 사용하면 element 의 값과 인덱스를 이용할 수 있다.

inline fun <T> Iterable<T>.filterIndexed(
   predicate: (index: Int, T) -> Boolean
): List<T>

filterNot() 은 predicate 가 false 인 조건의 element 를 사용한다.

fun <T : Any> Iterable<T?>.filterNotNull(): List<T>
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)

// output:
// [two, four]
// [three, four]

filterIsInstance() 주어진 타입의 collection 을 생성한다.

fun <reified R> Iterable<*>.filterIsInstance(): List<R>
val numbers = listOf(null, 1, "two", 3.0, "four")
println("All String elements in upper case:")
numbers.filterIsInstance<String>().forEach {
   println(it.toUpperCase())
}
println("Int:")
numbers.filterIsInstance<Int>().forEach {
   println(it)
}

// output:
// All String elements in upper case:
// TWO
// FOUR
// Int:
// 1

filterNotNull() non-null element 만 리턴한다.

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

// output:
// 3
// 3

Partitioning

partition() 은 매칭되는 element 와 그외의 element 들을 나누어 두개의 List 를 가지는 Pair 를 생성해 준다.

inline fun <T> Iterable<T>.partition(
   predicate: (T) -> Boolean
): Pair<List<T>, List<T>>
val numbers = listOf("one", "two", "three", "four")
val (match, rest) = numbers.partition { it.length > 3 }

println(match)
println(rest)

// output:
// [three, four]
// [one, two]

Testing predicates

predicate 를 테스트 하는 함수들

  • any() 적어도 한개의 element 가 매칭되면 true 리턴.

  • none() 매칭되는 element 가 없으면 true 리턴.

  • all() 모든 element 가 매칭 되면 true 리턴. empty collection 에 호출되도 true 를 리턴한다. vacuous truth.

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

// output:
// true
// true
// false
// true

any()none() 는 predicate 없이도 사용이 가능하다.

이 경우에는 collection 이 element 를 가지고 있는지 여부만 확인하면 된다.

element 가 있으면 any()true 를 리턴하고 그렇지 않으면 false 를 리턴한다. none() 는 반대로 동작.

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

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

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

// output:
// true
// false
// false
// true


Comments