Do it! 코틀린 프로그래밍 [셋째마당, 코틀린 표준 라이브러리의 활용] 학습
fun main() {
val list1: List<String> = listOf("one", "two", "three")
val list2: List<Int> = listOf(1, 3, 4)
val map1 = mapOf("hi" to 1, "hello" to 2, "Goodbye" to 3)
println(list1 + "four")
// list1 = [one, two, three, four]
println(list2 + 1)
// list2 = [1, 3, 4, 1]
println(list2 + listOf(5, 6, 7))
// list2 = [1, 3, 4, 5, 6, 7]
println(list2 - 1 )
// list2 = [3, 4]
println(list2 - listOf(3, 4, 5))
// list2 = [1]
println(map1 + Pair("Bye", 4))
// map1 = { hi=1, hello=2, Goodbye=3, Bye=4 }
println(map1 - "hello")
// map1 = { hi=1, Goodbye=3 }
println(map1 + mapOf("Apple" to 4))
// map1 = { hi=1, hello=2, Goodbye=3, Apple=4 }
println(map1 - listOf("hi", "hello"))
// map1 = { Goodbye=3 }
}
📌 요소의 순환
forEach
는 요소를 람다식으로 처리 후 컬렉션 반환 XonEach
는 요소를 람다식으로 처리하고 각 컬렉션을 반환// forEach (컬렉션 반환 X)
list.forEach { println("$it ") }
list.forEachIndexed { index, value -> println("index[$index] : $value") }
// onEach (컬렉션 반환)
val returnList = list.onEach { print(it) }
val returnMap = map.onEach { println ("key: ${it.key}, value: ${it.value}") }
📌 요소의 개수 반환
println(list.count { it % 2 == 0})
📌 최댓값과 최솟값의 요소 반환
println(list.max()) // 최댓값 요소
println(list.min()) // 최솟값 요소
println(map.maxBy { it.key }) // 키를 기준으로 최댓값
println(map.minBy { it.key }) // 키를 기준으로 최솟값
📌 각 요소에 정해진 식 적용
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.fold(4) { total, next -> total + next })
// 4 + 1 + 2 + ... + 6 = 25
println(list.fold(1) { total, next -> total * next })
// 1 * 1 * 2 * ... * 6 = 720
// fold와 같고 마지막 요소에서 처음 요소 순서로 적용
println(list.foldRight(4) { total, next -> total + next })
println(list.foldRight(1) { total, next -> total * next })
// fold와 같고 초깃값이 없음
println(list.reduce { total, next -> total + next })
// 1 + 2 + ... + 6 = 21
println(list.reduceRight { total, next -> total + next })
// 6 + 5 + ... + 1 = 21
📌 요소의 일치여부 검사하기
println(list.all { it < 10 })
println(list.any { it > 10})
📌 특정 요소의 포함 및 존재여부 검사
contains()
: 컬렉션에 특정 요소가 포함되어있는지 검사. 요소가 포함되어 있으면 true 반환containsAll()
: 모든 요소가 포함되어 있는지 검사none()
: 요소가 없으면 true 있으면 false 반환isEmpty()
: 컬렉션이 비어있으면 true를 반환isNotEmpty()
: 컬렉션이 비어있지 않으면 true를 반환val list = listOf(1, 2, 3, 4, 5, 6)
println(list.contains(2)) // true
println(2 in list) // true
println(map.contains(11)) // true
println(list.containsAll(listOf(1, 2, 3))) // true
println(list.none()) // false
println(list.isEmpty()) // false
println(list.isNotEmpty()) // true
📌 특정 요소를 골라내기
filterIndexed
: 특정 인덱스와 함께 추출filterIndexedTo
: filterIndexed
에 컬렉션으로 반환되는 기능 추가filterKeys
: 요소를 it으로 받아 키에 대한 조건에 맞는 부분을 반환filterValues
: 값에 의한 조건식을 만들고 그에 맞는 부분을 반환filterIsInstance<T>()
: 원하는 자료형을 골라내는 기능println(list.filter { it % 2 == 0}) // 짝수만 골라내기
println(list.filterNot { it % 2 == 0}) //식 이외의 요소 골라내기
println(list.filterNotNull()) // null을 제외
// 인덱스가 1이 아니고 짝수인 요소들
println(list.filterIndexed {idx, value -> idx != 1 && value % 2 == 0})
// 추출 후 가변형 컬렉션으로 변환
val mutList = list.filterIndexedTo(mutableListOf()) {idx, value -> idx != 1 && value % 2 == 0}
println(map.filterKeys {it != 11}) // 키 11을 제외한 요소
println(map.filterValues {it == "Java"}) 값이 "Java"인 요소
// listMixed = [1, "Hello", 3, 'A', "World"]
println(listMixed.filterIsInstance<String>()) // [Hello, World]
📌 특정 범위를 잘라내거나 반환하기
slice()
: 특정 범위의 인덱스를 가진 List를 인자로 사용해 기존 List에서 요소들을 잘라냄take()
: 앞에서부터 인자의 숫자만큼 반환takeLast()
: 뒤에서부터 인자의 숫자만큼 반환takeWhile()
: 조건식에 따라 반환val list = listOf(1, 2, 3, 4, 5, 6)
println(list.slice(listOf(0, 1, 2))) // [1, 2, 3]
println(list.take(2)) // [1, 2]
println(list.takeLast(2)) // [5, 6]
println(list.takeWhile{ it < 3}) // [1, 2]
📌 특정 요소 제외하기
drop()
: 앞에서부터 인자의 숫자만큼 제외println(list.drop(3)) // [4, 5, 6]
println(list.dropWhile { it < 3 }) // [3, 4, 5, 6]
println(list.dropLastWhile { it > 3 }) // [1, 2, 3]
📌 각 요소의 반환
componentN()
: N은 인덱스 번호가 아닌 1부터 시작하는 요소의 순서 번호list.component1
: 리스트의 첫 번째 요소인 1 반환list = listOf(1, 2, 3, 4, 5, 6)
📌 합집합과 교집합
distinct()
: 중복 요소가 있는 경우 1개로 취급하여 컬렉션 List로 반환intersect()
: 겹치는 요소만 골라내 List를 반환val listRepeated = listOf(2, 2, 3, 4, 5, 5, 6)
println(listRepeated.distinct()) // [2, 3, 4, 5, 6]
println(list.intersect(listOf(5, 6, 7,8))) // [5, 6]
📌 요소의 매핑
map()
: 컬렉션에 주어진 식을 적용해 새로운 컬렉션 반환mapIndexed
: 컬렉션에 인덱스를 포함하고 주어진 식을 적용해 새로운 컬렉션 반환mapNotNull
: null을 제외하고 식을 적용해 새로운 컬렉션 반환flatMap
: 각 요소에 식을 적용한 후 이것을 다시 하나로 합쳐 새로운 컬렉션을 반환groupBy
: 주어진 식에 따라 요소를 그룹화하고 이것을 다시 Map으로 반환val list = listOf(1, 2, 3, 4, 5, 6)
println(list.map { it * 2 }) // [2, 4, 5, 6, 10, 12]
val mapIndexed = list.mapIndexed { index, it => index * it }
// [0, 2, 6, 12, 20, 30]
val listWithNull = listOf(1, null, 3, null, 5, 6)
println(listWithNull.mapNotNUll { it?.times(2) }) // [2, 6, 10, 12]
println(list.flatMap { listOf(it, 'A')}) // [1,A,2,A,3,A,4,A,5,A,6,A]
val grpMap = list.groupBy{ it (it % 2 == 0) "even" else "odd"}
// even = [2, 4, 6], odd = [1, 3, 5]
elementAt()
: 인덱스에 해당하는 요소 반환elementAtOrElse()
: 인덱스를 벗어나는 경우 식에 따라 결과 반환elementAtOrNull()
: 인덱스를 벗어나는 경우 null 반환indexOf()
: 인자에 지정된 요소에 대한 첫 인덱스 반환indexOfFirst()
: 람다식에 일치하는 해당 요소 중 첫 번째 인덱스의 값을 반환. 해당하는 요소가 없으면 -1 반환indexOfLast()
: 람다식에 일치하는 해당 요소 중 마지막 인덱스의 값을 반환. 해당하는 요소가 없으면 -1 반환 binarySearch()
: 인자로 주어진 요소에 대해 이진 탐색 후 요소의 인덱스를 반환find
: 조건식을 만족하는 첫 번째 검색된 요소를 반환, 없으면 nullval list = listOf(1, 2, 3, 4, 5, 6)
println(list.elementAt(1)) // 2
println(list.elementAtOrElse(10, {2 * it}) // 20
println(list.elementAtOrNull(10)) // null
println(list.indexOf(4)) // 3 (4의 인덱스 넘버)
println(list.indexOfFirst { it % 2 == 0 }) // 1 (2의 인덱스 넘버)
println(list.indexOfLast { it % 2 == 0 }) // 5 (6의 인덱스 넘버)
println(list.binarySearch(3)) // 2
println(list.find { it > 3}) // 4
val listRepeated = listOf(2, 2, 3, 4, 5, 5, 6)
println(listRepeated.lastIndexOf(5)) // 5
first
: 식과 일치하는 첫 번째 요소 값 반환last
: 식과 일치하는 마지막 요소 값 반환firstOrNull
: 식에 일치하지 않는 경우 null 반환lastOrNull
: 식에 일치하지 않는 경우 null 반환single
: 조건식에 일치하는 요소를 하나 반환. 일치하는 요소가 하나 이상인 경우 예외 발생singleOrNull
: 조건식에 일치하는 요소가 없거나 일치하는 요소가 하나 이상이면 null을 반환val listPair = listOf(Pair("A", 200), Pair("B", 100), Pair("C", 200))
println(listPair.first { it.second == 200 }) // (A, 200)
println(listPair.last {it. second == 200 }) // (C, 200)
println(listPair.firstOrNull { it.first == "E" }) // null
println(listPair.lastOrNull { it.first == "E" }) // null
println(listPair.single { it.second == 100 }) // (B, 100)
println(listPair.singleOrNull {it.second == 200}) //null
union()
plus()
, +
연산자partition
zip()
val list1 = listOf(1, 2, 3, 4, 5, 6)
val list2 = listOf(2, 2, 3, 4, 5, 5, 6, 7)
println(list1.union(list2)) // [1, 2, 3, 4, 5, 6, 7]
println(list1.plus(list2)) // [1,2,3,4,5,6,2,2,3,4,5,5,6,7]
println(list1.partition { it % 2 == 0 }) // [2, 4, 6], [1, 3, 5]
val zip = list1.zip(listOf(7,8)) // zip = [(1, 7), (2, 8)]
reversed()
: 요소의 순서를 거꾸로 반환sorted()
sortedBy()
: 특정한 비교식에 의해 정렬된 컬렉션 반환sortedDescending
, sortedByDescending
val unsortedList = listOf(3, 2, 7, 5)
println(unsortedList.reversed()) // [5, 7, 2, 3]
println(unsortedList.sorted()) // [2, 3, 5, 7]
println(unsortedList.sortedDescending()) // [7, 5, 3, 2]
println(unsortedList.sortedBy { it % 3 }) // [3, 7, 2, 5]
println(unsortedList.sortedByDescending { it % 3 }) // [2, 5, 7, 3]
시퀀스(Sequence)란? 순차적인 컬렉션으로 요소의 크기를 특정하지 않고 나중에 결정할 수 있는 특수한 컬렉션
📌 generateSequence()로 생성하기
generateSequence()
: 시드(Seed) 인수에 의해 시작 요소의 값 결정val nums: Sequence<Int> = generateSequence(1) { it + 1 }
println(nums.take(10).toList())
// nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-> 시드 인수를 1로 지정하여 시작 요소의 값은 1
-> take(10)의 인자를 통해 원하는 개수만큼 요소가 저장
-> toList()를 통해 List 컬렉션으로 반환
📌 map, filter 연산 사용하기
val squares = generateSequence(1) {it + 1}.map { it * it}
println(squares.take(10).toList())
// [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
val oddSquares = squares.filter {it % 2 != 0}
println(oddSquares.take(5).toList())
// [1, 9, 25, 49, 81]
📌 메서드 체이닝의 중간 결과 생성하기
filter
나 map
을 메서드 체이닝해서 사용할 경우 순차적 연산이기 때문에 시간이 많이 걸릴 수 있음asSequence()
: 병렬 처리 되기 때문에 속도나 메모리 측면에서 처리 성능이 좋아짐val list1 = listOf(1, 2, 3)
val listDefault = list1
.map { it * it } // [1, 4, 9]
.filter { it % 2 == 0 } // [4]
/*
map(1)
map(2)
map(3)
filter(1)
filter(4)
filter(9)
[4]
*/
// asSequence() 사용
val listSeq = list1.asSequence()
.map { it * it }
.filter { it % 2 == 0 }
.toList()
/* 병렬처리
map(1) filter(1)
map(2) filter(4)
map(3) filter(9)
[4]
*/
📍 작은 컬렉션에서는 시퀀스 사용을 권장하지 않음