일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Class
- 다트
- function
- textstyle
- map
- kotlin
- python
- 콜렉션
- 웹크롤러
- 함수
- package
- List
- animation
- crawler
- ML
- variable
- 크롤러
- Collection
- 파이썬
- set
- 클래스
- pushnamed
- 코틀린
- Android
- Yocto
- Flutter
- import
- 플러터
- DART
- text
- Today
- Total
조용한 담장
코틀린(Kotlin) Collections : Transformations 본문
코틀린의 collection 의 transformation 에 대해 살펴보자.
원문 https://kotlinlang.org/docs/reference/collection-transformations.html 을 보며 정리.
한 collection 에서 다른 형태로 변형시키는 확장 함수들을 제공한다.
Mapping
다른 collection 의 element 로 부터 mapping transformation 을 만든다.
기본 함수는 map() 이다.
inline fun <T, R> Iterable<T>.map(
transform: (T) -> R
): List<R>
주어진 람다 함수를 각 element 에 적용하여 그 결과를 가진 List 를 리턴한다.
element 의 순서는 원본의 collection 과 같다.
mapIndexed() 를 사용하면 element 의 index를 argument 로 사용할 수 있다.
inline fun <T, R> Iterable<T>.mapIndexed(
transform: (index: Int, T) -> R
): List<R>val numbers = setOf(1, 2, 3)
println(numbers.map { it * 3 })
println(numbers.mapIndexed { idx, value -> value * idx })
// output:
// [3, 6, 9]
// [0, 2, 6]
특정 element 에서 null 이 결과로 생성되는 경우에는 map() 대신 mapNotNull(), mapIndexed() 대신 mapIndexedNotNull() 통해 걸러낼 수 있다.
val numbers = setOf(1, 2, 3)
println(numbers.mapNotNull { if ( it == 2) null else it * 3 })
println(numbers.mapIndexedNotNull { idx, value -> if (idx == 0) null else value * idx })
// output:
// [3, 9]
// [2, 6]
map 에 적용하는 경우엔 key 나 value 중 하나에는 transformation 이 안되도록 할 수 있다.
각각 mapKeys() 나 mapValues() 를 사용한다.
두 함수 모두 map entry 를 argument 로 사용하므로 map 의 key 와 value 모두를 이용할 수 있다.
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
println(numbersMap.mapKeys { it.key.toUpperCase() })
println(numbersMap.mapValues { it.value + it.key.length })
// output:
// {KEY1=1, KEY2=2, KEY3=3, KEY11=11}
// {key1=5, key2=6, key3=7, key11=16}
Zipping
두개의 collection 에서 같은 위치의 element 를 각각 가져와 pair들을 만든다.
확장함수 zip() 을 사용한다.
inline fun <T, R, V> Iterable<T>.zip(
other: Iterable<R>,
transform: (a: T, b: R) -> V
): List<V>
zip() 은 두개의 collection 또는 array 를 argument 로 가지고 호출되어 Pair object 들을 가진 List 를 리턴한다.
receiver collection (zip()이 호출되는 대상) 의 element 들은 zip() 의 결과로 만들어진 List 의 pair 들의 첫번째 element 들이 된다.
a.zip(b) 라면 a 의 element 가 Pair 의 첫번째 element 가 되어 [(a[0], b[0]]), (a[1], b[1]), ...] 구조로 만들어 진다.
collection 의 크기가 다른 경우 작은 크기로 만들어 지게 되며 큰 collection 의 나머지 element 들은 포함이 안되게 된다.
zip() 은 infix 형태인 a zip b 로 사용될 수 있다.
infix fun <T, R> Iterable<T>.zip(
other: Iterable<R>
): List<Pair<T, R>>
val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors zip animals)
// different sizes
val twoAnimals = listOf("fox", "bear")
println(colors.zip(twoAnimals))
// output:
// [(red, fox), (brown, bear), (grey, wolf)]
// [(red, fox), (brown, bear)]
zip() 을 두개의 parameters 를 가지는 transformation function 과 함게 사용할 수 있다.
이 경우에 결과 List 에는 receiver 의 pairs 와 같은 위치의 elements 값의 argument 를 가지고 호출된 transformation function 의 결과 값들이 저장되게 된다.
val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors.zip(animals) { color, animal -> "The ${animal.capitalize()} is $color"})
// output:
// [The Fox is red, The Bear is brown, The Wolf is grey]
Pair 들을 가진 List 가 있을 때 reverse transformation (unzipping) 을 통해 반대로 두개의 리스트로 분리할 수 있다.
대상 리스트의 각 Pair 의 첫번째 element 들과 두번째 element 들 만을 가진 리스트 두개로 구성된다.
unzip() 을 사용한다.
val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)
println(numberPairs.unzip())
// output:
// ([one, two, three, four], [1, 2, 3, 4])
Association
Assosication transformation 은 특정 값과 연관된 element 만 사용하여 map 을 만들수 있도록 한다.
다른 association type 들에 대해서는 element 들이 key 가 되거나 value 가 될 수 있다.
associateWith() 를 사용한다.
inline fun <K, V> Iterable<K>.associateWith(
valueSelector: (K) -> V
): Map<K, V>
collection 이 가지고 있는 기존의 값은 key 가 되고, transformation function 의 결과 들은 value 가 된다.
만약 두개의 element 동일한 경우에는 한개만 유지된다.
val numbers = listOf("one", "two", "three", "four")
println(numbers.associateWith { it.length })
// output:
// {one=3, two=3, three=5, four=4}
collection 의 element 를 value 로 사용하려면 associateBy() 를 사용한다.
inline fun <T, K> Iterable<T>.associateBy(
keySelector: (T) -> K
): Map<K, T>
inline fun <T, K, V> Iterable<T>.associateBy(
keySelector: (T) -> K,
valueTransform: (T) -> V
): Map<K, V>
val numbers = listOf("one", "two", "three", "four")
println(numbers.associateBy { it.first().toUpperCase() })
println(numbers.associateBy(keySelector = { it.first().toUpperCase() }, valueTransform = { it.length }))
println(numbers.associateBy({ it.first().toUpperCase() }, { it.toUpperCase() }))
// output:
// {O=one, T=three, F=four}
// {O=3, T=5, F=4}
// {O=ONE, T=THREE, F=FOUR}
Flattening
nested(중첩) collection 을 하나의 List 로 만들어 준다.
flatten() 을 사용한다.
fun <T> Iterable<Iterable<T>>.flatten(): List<T>
val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2))
println(numberSets.flatten())
// output:
// [1, 2, 3, 4, 5, 6, 1, 2]
원본 collection 에서 다른 collection 으로 매핑하는 함수를 받아 처리하는 flatMap() 을 사용하면 다양한 결과를 만들 수 있다.
val containers = listOf(
StringContainer(listOf("one", "two", "three")),
StringContainer(listOf("four", "five", "six")),
StringContainer(listOf("seven", "eight"))
)
println(containers.flatMap { it.values })
// output:
// [one, two, three, four, five, six, seven, eight]
String representation
collection 의 내용을 문자열로 바꿔주는 함수로 joinToString() 와 joinTo() 가 있다.
joinToString 는 String 을 리턴하고 joinTo 는 Appendable object 를 추가하여 리턴한다.
val numbers = listOf("one", "two", "three", "four")
println(numbers.toString())
println(numbers.joinToString())
val listString = StringBuffer("The list of numbers: ")
numbers.joinTo(listString)
println(listString)
// output:
// [one, two, three, four]
// one, two, three, four
// The list of numbers: one, two, three, four
separator, prefix, postfix 를 사용할 수 있다.
val numbers = listOf("one", "two", "three", "four")
println(numbers.joinToString(separator = " | ", prefix = "start: ", postfix = ": end"))
// output:
// start: one | two | three | four: end
limit 를 사용하여 element 의 수를 제한할 수 있다.
collection 의 크기가 limit 를 넘어가면, 다른 모든 element 는 truncated argument 의 하나의 값으로 대체된다.
val numbers = (1..100).toList()
println(numbers.joinToString(limit = 10, truncated = "<...>"))
// output:
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, <...>
transform 함수를 사용하여 element 의 표현을 다양하게 할 수 있다.
val numbers = listOf("one", "two", "three", "four")
println(numbers.joinToString { "Element: ${it.toUpperCase()}"})
// output:
// Element: ONE, Element: TWO, Element: THREE, Element: FOUR
'kotlin' 카테고리의 다른 글
코틀린(Kotlin) Collections : plus and minus Operators, Grouping (0) | 2020.03.27 |
---|---|
코틀린(Kotlin) Collections : Filtering (0) | 2020.03.24 |
코틀린(Kotlin) Collections : Operations Overview (0) | 2020.01.02 |
코틀린(Kotlin) Collections : 시퀀스(sequences) (0) | 2020.01.02 |
코틀린(Kotlin) Collections : Ranges and Progressions (0) | 2020.01.02 |