본문 바로가기
Program Language/Kotlin

[Do it! 코틀린 프로그래밍] 9. 컬렉션

by SungJe 2021. 5. 1.

9. 컬렉션


1. 컬랙션의 구조와 기본

컬렉션(Collection) 이란 자주 사용하는 기초적인 자료구조를 모아 놓은 일종의 프레임워크로 표준 라이브러리로 제공된다. Link

Collections Interface
  • 컬렉션 종류

    컬렉션 불변형(읽기 전용) 가변형
    List listOf mutableListOf, arrayListOf
    Set setOf mutableSetOf, hashSetOf, linkedSetOf, sortedSetOf
    Map mapOf mutableMapOf, hashMapOf, linkedMapOf, sortedMapOf
  • Collection 인터페이스 멤버

    멤버 설명
    size 컬렉션의 크기를 나타낸다.
    isEmpty() 컬렉션이 비어 있는 경우 true를 반환한다.
    contains(element: E) 특정 요소가 있다면 true를 반환
    containsAll(element: Collection<E>) 인자로 받아들인 Collection이 있다면 true를 반환한다.
  • MutableCollection 인터페이스 멤버 메서드

    멤버 메서드 설명
    add(element: E) 인자로 전달 받은 요소를 추가하고 true를 반환한다.
    이미 요소가 존재하면 false를 반환한다.
    remove(element: E) 인자로 전달 받은 요소를 삭제하고 true를 반환한다.
    요소가 존재하지 않으면 false를 반환한다.
    addAll(elements: Collection<E>) 컬렉션을 전달 받아 모든 요소를 추가하고 true를 반환한다.
    실패시 false를 반환한다.
    removeAll(elements: Collection<E> 컬렉션을 전달 받아 모든 요소를 삭제하고 true를 반환한다.
    실패시 false를 반환한다.
    retainAll(elements: Collection<E> 전달 받은 컬렉션의 요소만 보유하고 true를 반환한다.
    실패시 false를 반환한다.
    clear() 컬렉션의 모든 요소를 삭제한다.

2. List 활용하기

리스트(List) 란 순서에 따라 정렬된 요소를 가지는 컬렉션이다. 리스트는 헬퍼 함수를 통해 생성할 수 있으며, 인자는 원하는 만큼의 가변 인자로 선언할 수 있다. Link

불변형 List

  • 불변형 List 생성 핼퍼 함수

    • listOf(): 가변 인자를 받아 원하는 만큼 요소를 지정할 수 있다. List<T>를 반환하며 형식 매개변수를 지정하지 않으면 기본값인 <Any>를 사용한다.
    • emptyList(): 비어있는 List를 생성하기 위해 사용한다. 이때 반드시 형식 매개변수를 지정한다.
    • listOfNotNull(): null을 제외한 요소만 List로 구성한다.
  • List의 주요 멤버 메서드

    멤버 메서드 설명
    get(index: Int) 특정 인덱스를 인자로 받아 해당 요소를 반환한다.
    indexOf(element: E) 인자로 받은 요소가 첫 번째로 나타나는 인덱스를 반환하며,
    없으면 -1을 반환한다.
    lastIndexOf(element: E) 인자로 받은 요소가 마지막으로 나타나는 인덱스를 반환하며,
    없으면 -1을 반환한다.
    listIterator() 목록에 있는 iterator를 반환한다.
    subList(fromIndex: Int, toIndex: Int) 특정 인덱스의 from과 to 범위에 있는 요소 목록을 반환한다.
/* 구조 */
public fun <T> listOf(vararg elements: T): List<T>

/* 불변형 List 사용하기 */
val numbers = listOf(1, 2, 3, 4, 5) // List<Int>형으로 추론
val emptyList: List<String> = emptyList<String>() // 빈 List 생성
val nonNullsList: List<String> = listOfNotNull("one", "two", null, "three", null) // null이 아닌 요소만 구성

// 컬렉션 반복
for (number in numbers) {
    print("$number ")
}
println()

for (index in nonNullsList.indices) { 
    println("nonNullsList[$index] = ${nonNullsList[index]}")
}

가변형 List

  • 가변형 List 생성 핼퍼 함수

    • arrayListOf(): 가변형 List를 생성하지만 반환 자료형은 자바의 ArrayList다.
    • mutableListOf(): 코틀린의 MutableList 인터페이스를 사용하는 헬퍼 함수다.
/* 구조 */
public fun <T> arrayListOf(vararg elements: T): ArrayList<T>
public fun <T> mutableListOf(vararg elements: T): MutableList<T>

/* 가변형 List 사용하기 */
import java.util.ArrayList

val stringList: ArrayList<String> = arrayListOf<String>("Hello", "Kotlin", "Wow")
stringList.add("Java") // 추가
stringList.remove("Hello") // 삭제
println(stringList) // [Kotlin, Wow, Java]

val mutableList: MutableList<Int> = mutableListOf<Int>(1, 2, 3)
mutableList.add(4) // 추가
mutableList.removeAt(1) // 인덱스 1번 삭제
mutableList[0] = 5
println(mutableList) // [5, 3, 4]

/* 불변형 List를 가변현으로 변환하기 */
val names: List<String> = listOf("one", "two", "three") // 불변형 List
val mutableNames = names.toMutableList() // 새로운 가변형 List 생성
mutableNames.add("four") // 요소 추가
println(mutableNames) // [one, two, three, four]

NOTE✏️

  • 헬퍼 함수(Helper Function): 보통 List와 같은 컬렉션은 직접 사용해 생성하지 않고 특정 함수의 도움을 통해 생성하는데 이때 사용하는 함수를 말한다.

3. Set과 Map 활용하기

셋(Set) 이란 정해진 순서가 없는 요소들의 집합을 나타내는 컬렉션이다. 집합의 개념이기 때문에 모든 요소가 유일(unique)해야 한다. Link

  • 생성 헬퍼 함수

    핼퍼 함수 설명
    setOf() 불변형 Set인 Set<T> 자료형을 반환한다.
    mutableSetOf() 가변형 Set인 MutableSet<T> 자료형을 반환하지만,
    내부적으로자바의 LinkedHashSet을 생성한다.
  • 불변형 Set

/* setOf() 함수 사용하기 */
val intSet: Set<Int> = setOf<Int>(1, 5, 5)
println(intSet) // [1, 5] - 중복 요소(5)를 혀용하지 않는다.
  • 가변형 Set
/* mutableSetOf() 함수 사용하기 */
val animals = mutableSetOf("Lion", "Dog", "Cat", "Python", "Hippo")
animals.add("Dog") // 요소 추가 - "Dog"는 이미 존재하므로 변화 없음
animals.remove("Python") // 요소 삭제
println(animals) // [Lion, Dog, Cat, Hippo]
  • Set을 위한 기타 자료구조

    생성 헬퍼 함수

    핼퍼 함수 설명
    hashSetOf() 해시 테이블에 요소를 자장할 수 있는 자바의 HashSet 컬렉션을 생성한다.
    요소의 추가와 삭제가 가능하며 O(1) 시간복잡도의 검색 속도를 갖는다.
    sortedSetOf() 자바의 TreeSet 컬렉션을 정렬된 상태로 반환한다.
    HashSet보다 성능이 조금 떨어지지만 검색과 정렬이 뛰아나다는 장점이 있다.
    linkedSetOf() 자바의 LinkedHashSet 자료형을 반환한다.
    링크드 리스트(Linked List) 자료구조를 사용해 구현된 해시 테이블에 요소를 저장한다.
/* hashSetOf() 함수 사용하기 */
val intsHashSet: HashSet<Int> = hashSetOf(6, 3, 4, 7)
intsHashSet.add(5) // 요소 추가
intsHashSet.remove(6) // 요소 삭제
println(intsHashSet) // [3, 4, 5, 7]

/* sortedSetOf() 함수 사용하기 */
import java.util.TreeSet

val intsSortedSet: TreeSet<Int> = sortedSetOf(4, 1, 7, 2)
intsSortedSet.add(6) // 요소 추가
intsSortedSet.remove(1) // 요소 삭제
println(intsSortedSet) // [2, 4, 6, 7]

/* linkedSetOf() 함수 사용하기 */
import java.util.LinkedHashSet

val intsLinkedHashSet: LinkedHashSet<Int> = linkedSetOf(35, 21, 76, 26, 75)
intsLinkedHashSet.add(4) // 요소 추가
intsLinkedHashSet.remove(21) // 요소 삭제
println(intsLinkedHashSet) // [35, 76, 26, 75, 4]

NOTE✏️

  • 해시 테이블(Hash Table): 키를 값에 매핑할 수 있는 구조인, 연관 배열 추가에 사용되는 자료 구조다. Link
  • 트리 셋(Tree Set): 저장된 데이터의 값에 따라 정렬되는 레드 블랙 트리 알고리즘을 사용해 자료구조를 구성한다.
  • 레드 블랙 트리(RB tree: Red-Black tree): 연관 배열 등을 구현하는 데 쓰이는 자료구조다. O(log n)의 시간복잡도로 삽입, 삭제, 검색을 할 수있다. Link
  • 연결 리스트(Linked List): 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식으로 데이터를 저장하는 자료 구조다. Link

맵(Map) 이란 요소가 키(Key)와 값(Value)의 쌍 형태로 저장된다. 키는 중복될 수 없고 유일하지만 값은 중복될 수 있다.

  • 생성 헬퍼 함수

    핼퍼 함수 설명
    mapOf() 불변형 Map 컬렉션을 만들 수 있다.
    mutableMapOf() 추가, 삭제가 가능한 가변형 Map을 정의한다.
  • 불변형 Map

    멤버 프로퍼티와 메서드

    멤버 설명
    size Map 컬렉션의 크기를 반환한다.
    keys Map의 모든 키를 반환한다.
    values Map의 모든 값을 반환한다.
    isEmpty() Map이 비어 있는지 확인한다. 비어있으면 true, 아니면 false를 반환한다.
    containsKey(key: K) 인자에 해당하는 키가 있으면 true, 아니면 false를 반환한다.
    containsValue(value: V) 인자에 해당하는 값가 있으면 true, 아니면 false를 반환한다.
    get(key: K) 키에 해당하는 값을 반환한다. 존재하지 않으면 null을 반환한다.
/* 구조 */
val map: Map<키 자료형, 값 자료형> = mapOf(키 to 값[, ...])

/* mapOf() 함수 사용하기 */
val langMap: Map<Int, String> = mapOf(11 to "Java", 22 to "Kotlin", 33 to "C++")
for ((key, value) in langMap) { // 키와 값의 쌍을 출력
    println("key=$key, value=$value")
}
println("langMap[22] = ${langMap[22]}") // 키 22에 대한 요소 출력
println("langMap.get(22) = ${langMap.get(22)}") // 위와 동일한 표현
println("langMap.keys = ${langMap.keys}") // 맵의 모든 키 출력
  • 가변형 Map

    멤버 메서드

    멤버 설명
    put(key: K, value: V) 키와 값의 쌍을 Map에 추가한다.
    remove(key: K) 키에 해당하는 요소를 Map에서 제거한다.
    putAll(from: Map<out K, V>) 인자로 주어진 Map 데이터를 갱신하거나 추가한다.
    clear() 모든 요소를 지운다.
/* mutableMapOf() 함수 사용하기 */
val capitalCityMap: MutableMap<String, String>
        = mutableMapOf("Korea" to "Seoul", "China" to "Beijing", "Japan" to "Tokyo")

println(capitalCityMap.keys) // 키 출력 - [Korea, China, Japan]
println(capitalCityMap.values) // 값 출력 - [Seoul, Beijing, Tokyo]
capitalCityMap.put("UK", "London") // 요소 추가
capitalCityMap.remove("China") // 요소 삭제
println(capitalCityMap) // 맵 출력 - {Korea=Seoul, Japan=Tokyo, UK=London}

val addData = mutableMapOf("USA" to "Washington")
capitalCityMap.putAll(addData)
println(capitalCityMap) // {Korea=Seoul, Japan=Tokyo, UK=London, USA=Washington}
  • Map을 위한 기타 자료구조

    생성 헬퍼 함수

    핼퍼 함수 설명
    hashMapOf() 해시 테이블에 요소를 자장할 수 있는 자바의 HashMap 컬렉션을 생성한다.
    sortedMapOf() 자바의 TreeMap 컬렉션을 정렬된 상태로 반환한다.
    linkedMapOf() 자바의 LinkedHashMap 자료형을 반환한다.
/* hashMapOf() 함수 사용하기 */
import java.util.HashMap

val hashMap: HashMap<Int, String> = hashMapOf(1 to "Hello", 2 to "World")
println("hashMap = $hashMap") // hashMap = {1=Hello, 2=World}

/* sortedMapOf() 함수 사용하기 */
import java.util.SortedMap

val sortedMap: SortedMap<Int, String> = sortedMapOf(1 to "Apple", 2 to "Banana")
println("sortedMap = $sortedMap") // sortedMap = {1=Apple, 2=Banana}

/* linkedMapOf() 함수 사용하기 */
import java.util.LinkedHashMap

val linkedHash: LinkedHashMap<Int, String> = linkedMapOf(1 to "Computer", 2 to "Mouse")
println("linkedHash = $linkedHash") // linkedHash = {1=Computer, 2=Mouse}

4. 컬랙션의 확장 함수

확장 함수 범주

  • 연산자(Operators) 기능의 메서드: 더하고 빼는 등의 연산 기능
  • 집계(Aggregators) 기능의 메서드: 최대, 최소, 집합, 총합 등의 계산 기능
  • 검사(Checks) 기능의 메서드: 요소를 검사하고 순환하기 위한 기능
  • 필터(Filtering) 기능의 메서드: 원하는 요소를 골라내기 위한 기능
  • 변환(Transformers) 기능의 메서드: 뒤집기, 정렬, 자르기 등의 변환 기능

컬렉션의 연산

val numbers = listOf("one", "two", "three") // 불변형 List

// 연산의 결과는 새로운 컬렉션을 만든다.
println(numbers + "four") // + 연산자를 사용하여 요소를 더함
println(numbers - "two") // - 연산자를 사용하여 요소를 뺌
println(numbers + listOf("Hello", "Kotlin")) // listOf() 함수를 사용하여 두 List를 병합

요소의 처리와 집계

  • 요소의 순환
val list = listOf(1, 2, 3, 4, 5, 6)

// forEach: 각 요소를 람다식으로 처리
list.forEach { print("$it ") }
println()

// forEachIndexed: 각 요소를 람다식으로 처리하며, 인자로 인덱스와 값을 받음
list.forEachIndexed { index, value -> println("index[$index]: $value") }

// onEach: 각 요소를 람다식으로 처리 후 컬렉션으로 반환
val returnedList = list.onEach { print(it) }
println()
println("returnedList = $returnedList")
  • 모든 요소의 합산 및 요소의 개수, 최댓값과 최솟값 반환하기
val list = listOf(1, 2, 3, 4, 5, 6)

// sumBy: 식에 의해 도출된 모든 요소를 합산
println(list.sumBy { it }) // 21

// count: 람다식 함수를 조건으로 요소 개수 반환
println(list.count { it % 2 == 0 }) // 3

// maxOrNull/minOrNull: 최댓값/최솟값 요소를 반환하며, 요소가 없는경우 null을 반환
println(list.maxOrNull()) // 6
println(list.minOrNull()) // 1

// maxByOrNull/minByOrNull: 람다식 함수를 조건으로 최댓값/최솟값 요소를 반환하며, 요소가 없는경우 null을 반환
println("maxByOrNull: " + map.maxByOrNull { it.key }) // 키를 기준으로 최댓값
println("minByOrNull: " + map.minByOrNull { it.key }) // 키를 기준으로 최솟값
  • 각 요소에 정해진 식 적용하기
val list = listOf(1, 2, 3, 4, 5, 6)

// fold: 초깃값과 정해진 식에 따라 처음 요소부터 끝 요소에 적용하며 값을 생성
println(list.fold(4) { total, next -> total + next }) // 4 + 1 + ... + 6 = 25
println(list.fold(1) { total, next -> total * next }) // 1 * 1 * ... * 6 = 720

// foldRight: fold와 같고 마지막 요소에서 처음 요소로 반대로 적용
println(list.foldRight(4) { total, next -> total + next }) // 4 + 6 + ... + 1 = 25
println(list.foldRight(1) { total, next -> total * next }) // 1 * 6 * ... * 1 = 720

// reduce: fold와 동일하지만 초깃값을 사용하지 않음
println(list.reduce { total, next -> total + next }) // 1 + 2 + ... + 6 = 21
println(list.reduceRight { total, next -> total + next }) // 6 + 5 + ... + 1 = 21

요소의 검사

  • 요소의 일치 여부 검사하기
val list = listOf(1, 2, 3, 4, 5, 6)

// all: 모든 요소가 람다식의 조건을 일치해야 true를 반환
println(list.all { it < 10 }) // true
println(list.all { it % 2 == 0 }) // false

//  any: 최소 하나 혹은 그 이상의 요소가 람다식의 조건에 일치해야 true를 반환
println(list.any { it % 2 == 0 }) // true
println(list.any { it > 10 }) // false
  • 특정 요소의 포함 및 존재 여부 검사하기
val list = listOf(1, 2, 3, 4, 5, 6)
val emptyList = emptyList<Int>()

// contains: 요소가 포함되어 있으면 true를 반환
println("contains: " + list.contains(2)) // true
println(7 in list) // false

// containsAll: 모든 요소가 포함되어 있으면 true를 반환
println("containsAll: " + list.containsAll(listOf(3, 5, 6))) // true

// none: 요소가 없으면 true, 있으면 false를 반환
println("none: " + list.none()) // false
println("none: " + emptyList.none()) // true
println("none: " + list.none { it > 6 }) // 6 이상은 없으므로 true

// isEmpty/isNotEmpty: 컬렉션이 비어 있는지 아닌지 검사
println(list.isEmpty()) // false
println(list.isNotEmpty()) // true

요소의 필터와 추출

  • 특정 요소를 골라내기
val list = listOf(1, 2, 3, 4, 5, 6)
val listWithNull = listOf(1, null, 3, null, 5, 6)
val listMixed = listOf(1, "Hello", 3, "World", 5, 'A')
val map = mapOf(11 to "Java", 22 to "Kotlin", 33 to "C++")

// filter: 람다식의 조건에 따라 요소 골라내기
println(list.filter { it % 2 == 0 }) // [2, 4, 6]
println(list.filterNot { it % 2 == 0 }) // [1, 3, 5]
println(listWithNull.filterNotNull()) // [1, 3, 5, 6]

// filterIndexed: 인덱스와 함께 추출
println("filterIndexed: " + list.filterIndexed { index, value ->
    index != 1 && value % 2 == 0
}) // [4, 6]

// filterIndexedTo: 추출 후 가변형 컬렉션으로 반환
val mutableList = list.filterIndexedTo(mutableListOf()) { index, value -> index != 1 && value % 2 == 0 }
println("filterIndexedTo: $mutableList") // [4, 6]

// filterKeys/filterValues: Map의 키, 값에 따라 추출
println("filterKeys: " + map.filterKeys { it != 11 }) // {22=Kotlin, 33=C++}
println("filterValues: " + map.filterValues { it == "Java" }) // {11=Java}

// filterIsInstance: 여러 자료형의 요소 중 원하는 자료형을 골라냄
println("filterIsInstance: " + listMixed.filterIsInstance<String>()) // [Hello, World]
  • 특정 범위를 잘라내거나 반환하기
val list = listOf(1, 2, 3, 4, 5, 6)

// slice: 특정 인덱스의 요소들을 잘라서 반환하기
println("slice: " + list.slice(listOf(0, 2, 5))) // [1, 3, 6]

// take: n개의 요소를 반환
println(list.take(2)) // [1, 2] - 앞의 2개 요소
println(list.takeLast(2)) // [5, 6] - 뒤의 2개 요소
println(list.takeWhile { it < 4 }) // [1, 2, 3] - 조건의 요소

// drop: 처음부터 n개의 요소를 제외한 List 반환
println(list.drop(4)) // [5, 6] - 앞의 4개 제외한 요소
println(list.dropWhile { it < 3 }) // [3, 4, 5, 6] - 앞의 조건의 요소 제외
println(list.dropLastWhile { it > 3 }) // [1, 2, 3] - 뒤의 조건의 요소 제외
  • 각 요소의 반환
val list = listOf(1, 2, 3, 4, 5, 6)

// componentN: 요소의 순서 번호를 반환
println("component2(): " + list.component2()) // 2
println("component5(): " + list.component5()) // 5
  • 합집합과 교집합
val list = listOf(1, 2, 3, 4, 5, 6)

// distinct: 중복 요소는 하나로 취급하여 List 반환
println("distinct: " + listOf(2, 2, 3, 4, 5, 5).distinct()) // [2, 3, 4, 5]

// intersect: 교집합 요소만 골라냄
println("intersect: " + list.intersect(listOf(5, 6, 7, 8))) // [5, 6]

요소의 매핑

val list = listOf(1, 2, 3, 4, 5, 6)
val listWithNull = listOf(1, null, 3, null, 5, 6)

// map: 컬렉션에 주어진 식을 적용해 새로운 컬렉션을 반환
println(list.map { it * 2 }) // [2, 4, 6, 8, 10, 12]

// mapIndexed: 컬렉션에 인덱스를 포함해 주어진 식을 적용해 새로운 컬렉션 반환
val mapIndexed = list.mapIndexed { index, element -> index * element } // [0, 2, 6, 12, 20, 30]
println(mapIndexed)

// mapNotNull: null을 제외하고 식을 적용해 새로운 컬렉션 반환
println(listWithNull.mapNotNull { it?.times(2) }) // [2, 6, 10, 12]

// flatMap: 각 요소에 식을 적용 후 다시 합쳐 새로운 컬렉션을 반환
println(list.flatMap { listOf(it, 'A') }) // [1, A, 2, A, 3, A, 4, A, 5, A, 6, A]
val result = listOf("abc", "12").flatMap { it.toList() }
println(result) // [a, b, c, 1, 2]

// groupBy: 주어진 함수의 결과에 따라 그룹화하여 map으로 반환
val groupMap = list.groupBy { if (it % 2 == 0) "even" else "odd" }
println(groupMap) // {odd=[1, 3, 5], even=[2, 4, 6]}

요소 처리와 검색

val list = listOf(1, 2, 2, 4, 5, 5, 7)
val listPair = listOf(Pair("A", 300), Pair("B", 200), Pair("C", 100), Pair("D", 200))

// elementAt: 인덱스에 해당하는 요소 반환
println("elementAt: " + list.elementAt(1)) // 2

// elementAtOrElse: 인덱스를 벗어나는 경우 식의 결과를 반환에 따라 결과 반환
println("elementAtOrElse: " + list.elementAtOrElse(10) { 2 * it }) // 20

// elementAtOrNull: 인덱스를 벗어나는 경우 null 반환
println("elementAtOrNull: " + list.elementAtOrNull(10)) // null

// first: 식에 일치하는 첫 요소 반환
println("first: " + listPair.first { it.second == 200 }) // (B, 200)

// last: 식에 일치하는 마지막 요소 반환
println("last: " + listPair.last { it.second == 200 }) // (D, 200)

// firstOrNull: 식에 일치하지 않는 경우 null 반환
println("firstOrNull: " + listPair.firstOrNull() { it.first == "E" }) // null

// lastOrNull: 식에 일치하지 않는 경우 null 반환
println("lastOrNull: " + listPair.lastOrNull() { it.first == "E" }) // null

// indexOf: 주어진 요소에 일치하는 첫 인덱스 반환
println("indexOf: " + list.indexOf(4)) // 3

// indexOfFirst: 람다식에 일치하는 첫 요소의 인덱스 반환, 없으면 -1
println("indexOfFirst: " + list.indexOfFirst { it % 2 == 0 }) // 1

// lastIndexOf: 주어진 요소에 일치하는 가장 마지막 인덱스 반환
println("lastIndexOf: " + list.lastIndexOf(5)) // 5

// indexOfLast: 람다식에 일치하는 마지막 요소의 인덱스 반환, 없으면 -1
println("indexOfLast: " + list.indexOfLast { it % 2 == 0 }) // 3

// single: 람다식에 일치하는 요소 하나 반환
println("single: " + listPair.single { it.second == 100 }) // (C, 100)
println("singleOrNull: " + listPair.singleOrNull { it.second == 500 }) // null

// binarySearch: 요소에 대해 이진 탐색 후 인덱스 반환
println("binarySearch: " + list.binarySearch(4)) // 3

// find: 조건식을 만족하는 첫 번째 검색된 요소 반환, 없으면 null
println("find: " + list.find { it > 3 }) // 4

컬렉션의 분리와 병합

val list1 = listOf(1, 2, 3, 4)
val list2 = listOf(2, 2, 3, 4, 5, 5)

// union: 두 List를 병합(중복 요소는 하나만)
println(list1.union(list2)) // [1, 2, 3, 4, 5]

// plus: 두 List를 병합(중복 요소 포함), + 연산자와 동일 연산
println(list1.plus(list2)) // [1, 2, 3, 4, 2, 2, 3, 4, 5, 5]

// partition: 주어진 식에 따라 2개의 컬렉션으로 분리해 Pair로 반환
val part = list1.partition { it % 2 == 0 }
println(part) // ([2, 4], [1, 3])

// zip: 동일 인덱스끼리 Pair를 만들어 반환
val zip = list1.zip(list2)
println(zip) // [(1, 2), (2, 2), (3, 3), (4, 4)]

순서와 정렬

val unsortedList = listOf(3, 2, 7, 5)

// reversed: 뒤집힌 순서로 컬렉션 반환
println(unsortedList.reversed()) // [5, 7, 2, 3]

// sorted: 요소를 정렬한 후 정렬된 컬렉션 반환
println(unsortedList.sorted()) // [2, 3, 5, 7]

// sortedDescending: 내림차순 정렬
println(unsortedList.sortedDescending()) // [7, 5, 3, 2]

// sortedBy: 특정 비교식에 의해 정렬된 컬렉션 반환환
println(unsortedList.sortedBy { it % 3 }) // [3, 7, 2, 5]
println(unsortedList.sortedByDescending { it % 3 }) // [2, 5, 7, 3]

5. 시퀀스 활용하기

시퀀스(Sequence) 란 순차적인 컬렉션으로 요소의 크기를 특정하지 않고, 나중에 결정할 수 있는 특수한 컬렉션이다. 처리 중에는 계산하지 않다가 toList()나 count() 같은 최종 연산에 의해 결정된다.

  • 요소 값 생성하기
// generateSequence: 시드 값을 시작으로 특정 값을 생성하는 시퀀스 정의
val numbers: Sequence<Int> = generateSequence(1) { it + 1 }

// take: 원하는 요소 개수만큼 획득
println(numbers.take(10).toList()) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

/* 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]
  • 요소 값 가져오기
val list = listOf(1, 2, 3, 4, 5)

/* 단순 메서드 체이닝 */
val listDefault = list
    .map { it * it }
    .filter { it % 2 == 0 }
println(listDefault) // [4, 16]

/* asSequence() 사용하기 */
// asSequence: 중간 연산 결과 없이 한 번에 끝까지 연산한 후 결과를 반환
// 병렬 처리로 속도나 메모리 측면에서 우수하나 작은 크기의 컬렉션에는 효율이 낮음
val listSequence = list.asSequence()
    .map { it * it }
    .filter { it % 2 == 0 }
    .toList()
println(listSequence) // [4, 16]

NOTE✏️

  • 자료형 별칭(Type Alias): 코드의 가독성을 높이기 위해 특정 자료형에 대한 대체할 수 있는 이름을 제공하는 기능이다. 코틀린은 typealias 키워드를 이용해 복잡한 자료형을 간략하게 줄여서 표현할 수 있다.
typealias NodeSet = Set<Network.Node>
typealias FileTable<K> = MutableMap<K, MutableList\<File>>