chacha's

컬렉션(Collections) 본문

Kotlin

컬렉션(Collections)

Cha_Cha 2021. 9. 12. 17:15

목차

     Kotlin In Action - 책
     과 아래에 링크된 게시글을 참고하여 작성한 게시글입니다.
    컬렉션에 대해 공부하기 위한 게시글입니다. 
    👉 원문을 보는 것을 추천드립니다!!
     

    Kotlin Collection 함수

    코틀린의 컬렉션 함수들을 그림과 함께 쉽게 알아봅니다.

    medium.com

    📌 컬렉션을 보기 전에, 컬렉션에 들어갈 수 있는 Basic types을 봅시다! 

     

    Basic types | Kotlin

     

    kotlinlang.org

     

     Collections의 종류

     Kotlinloang.org/docs

    코틀린의 Collection은 Java와 매우 유사하지만, Mutable과 Immutable을 구분하여 지원한다는 점이 다릅니다.

    Kotlin collections 상속 구조

    • List는 데이터를 저장하거나 삭제할 때 순서를 지키는 컬렉션입니다. [ C++의 Vector와 유사하다고 생각하면 될 것 같습니다. ]
    • Set은 동일한 아이템이 없는 컬렉션입니다. 따라서 Set의 아이템들은 순서가 특별히 정해져 있지 않습니다. Set의 기본 구현은 LinkedHashSet입니다.
    • MapKey-Value Pair(or entries)를 저장하는 컬렉션입니다. key 값은 유일하기 때문에 key가 동일한 element를 추가할 수 없습니다. Map의 기본 구현은 LinkedHashMap입니다.

    Kotlin의 컬렉션은 제네릭(Generic)으로 구현이 되어 있기 때문에 다양한 타입으로 사용할 수 있습니다.

    Kotlin의 컬렉션은 기본적으로 MutableImmutable을 별개로 지원합니다.

    • 그냥 List/Set/Map으로 생성할 경우, 읽기 전용(read-only)로 생성되기 때문에 삽입/삭제가 불가능합니다. 
    • Mutable한 컬렉션으로 변경한다고 해서 var로 선언할 필요는 업습니다. 요소를 삽입/삭제를 한다고 해서 참조가 변경되지 않습니다. 또한 이미 val로 선언된 컬렉션을 다시 할당하려고 하면 컴파일 오류가 발생합니다.
    val numbers = mutableListOf("one", "two", "three", "four")
    numbers.add("five")
    
    // 아래는 컴파일 오류가 발생합니다.
    // numbers = mutableListOf("six", "seven")

     

    💡 Array? ArrayList? List?

    List는 Array와 매우 유사합니다. 하지만 Array의 크기는 초기화 시점과 동시에 정의되며 변경되지 않습니다. 하지만 List는 사전적으로 정의된 크기를 가지지 않습니다. 따라서 요소(element)를 추가, 업데이트, 삭제하는 등의 쓰기 연산(write operation)을 통해 리스트의 크기를 변경할 수 있습니다.

    더보기

    # 📌 Array 선언과 ArrayList 선언의 차이 [접은 글]

    /* Array */
    val x: IntArray = intArrayOf(1, 2, 3)
    val arr = IntArray(5) // [0, 0, 0, 0, 0]
    val arr = IntArray(5) { 42 } // [42, 42, 42, 42, 42]
    var arr = IntArray(5) { it * 1 } // [0, 1, 2, 3, 4]
    
    var arr = intArrayOf(1, 2, 3, 4) // [1, 2, 3, 4]
    var arr = Array(10, { i -> 1 }) // [ 1, 1, ... , 1 ]
    val intArr: Array<Int> = arrayOf(1, 2, 3) // [1, 2, 3]
    
    
    /* ArrayList */
    val list = arrayListOf(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]
    val list = arrayListOf<Int>()
    list.addAll(listOf(1, 2, 3)) // [1, 2, 3]

    # 📌 Array 선언과 ArrayList 선언의 차이 [닫기]

    더보기

    # 📌 2차원 배열 생성하기

    var matrix2D: Array<IntArray> = Array(height) { IntArray(width) }
    var matrix3D = Array(5){ Array(5){ Array(5){1} } }

    # 📌 2차원 배열 생성하기

     

    📚 Collection 함수의 종류

    출처 :&nbsp;https://medium.com/mobile-app-development-publication/kotlin-collection-functions-cheat-sheet-975371a96c4b

     

    1️⃣ Collection 생성을 위한 함수 종류 ( Creation )

     Kotlin의 Collection 함수   

    아래의 코드들은 코틀린에서 컬렉션을 인스턴스화 하는 함수 목록입니다.

    // 비어있는 컬렉션
    emptyList, emptyMap, emptySet

    // 읽기 전용 컬렉션
    listOf, mapOf, setOf

    // 변경 가능한 컬렉션
    mutableListOf, mutableMapOf, mutableSetOf, arrayListOf

    // 다른 소스를 첨가할 수 있는 빌드 컬렉션
    buildList, buildMap, buildSet

    // Linked 컬렉션
    linkedMapOf, linkedSetOf

    // 정렬된 컬렉션
    sortedMapOf, sortedSetOf

    // Hash 컬렉션
    hashMapOf, hashSetOf

    // 프로그래밍 방식으로 컬렉션 만들기
    List, MutableList, Iterable
    더보기

    # 📌 Map 생성하기

    val numbersMap = mapOf<String, String>("1" to "one", "2" to "two", "3" to "three")
    val numbersMap2 = mapOf(Pair("1", "one"), Pair("2", "two"), Pair("3", "three"))

    # 📌 Map 생성하기

     

     linkedSetOf과 hashSetOf의 차이

     What's the different between linkedSetOf and hashSetOf? - stack overflow

    linkedSetOfLinkedHashSet을 반환하고 hashSetOfHashSet을 반환합니다.

    🤔 그렇다면 LinkedHashSetHashSet의 차이점은 무엇일까요? 

    LinkedHashSet은 삽입될 때의 순서를 유지하는 컬렉션입니다. 삽입 순서를 따로 저장합니다.  반면에 HashSet은 요소의 순서를 유지하지 않습니다. 요소의 순서에 대해 아무것도 알려주지 않으므로, 동일한 수의 요소를 저장할 때 더 적은 메모리를 필요로 합니다. 이러한 특징은 LinkedHashMap,HashMap도 동일합니다. ( Kotlin playground

    /* LinkedHashSet */
    val set: LinkedHashSet<Int> = linkedSetOf(1, 3, 2)
    
    println(set) // [1, 3, 2]
    
    set.remove(3)
    set += listOf(5, 4)
    println(set) // [1, 2, 5, 4]
    
    /* HashSet */
    val hashSet: HashSet<Int> = hashSetOf(1, 3, 2)
    
    println(hashSet) // [1, 2, 3]
    
    hashSet.remove(3)
    hashSet += listOf(5, 4)
    println(hashSet) // [1, 2, 4, 5]

    위의 예제만 참고하면 HashSet이 SortedSet과 무엇이 다른가 싶습니다. 하지만 HashSet은 요소를 정렬하지 않습니다. 아래의 코드를 통해 이를 확인할 수 있습니다. ( Kotlin playground )

    /* LinkedHashSet */
    val linkedHashSet = linkedSetOf("aaa","bbb","ccc")
    
    println(linkedHashSet) // [aaa, bbb, ccc]
    
    linkedHashSet.remove("ccc")
    linkedHashSet += listOf("ddd","zzz")
    println(linkedHashSet) // [aaa, bbb, ddd, zzz]
    
    /* HashSet */
    val hashSet = hashSetOf("aaa","bbb","ccc")
    
    println(hashSet) // [aaa, ccc, bbb]
    
    hashSet.remove("ccc")
    hashSet += listOf("ddd","zzz")
    println(hashSet) // [aaa, bbb, zzz, ddd]

     

    3️⃣ Collection 타입 변경 ( Change )

    컬렉션을 다른 타입으로 변경하려고 시도하는 함수 목록입니다.

    출처 :&nbsp;https://medium.com/mobile-app-development-publication/kotlin-collection-functions-cheat-sheet-975371a96c4b

     toIntArray()

    다른 타입의 새 컬렉션으로 변환하는 함수 목록입니다.

    // 배열 타입으로 복사
    toBooleanArray, toByteArray, toCharArray, toDoubleArray, toFloatArray, toIntArray, toLongArray, toShortArray, toTypedArray, toUByteArray, toUIntArray, toULongArray, toUShortArray

    // 읽기 전용 컬렉션으로 복사
    toList, toMap, toSet

    // 변경 가능한 컬렉션으로 복사
    toMutableList, toMutableMap, toMutableSet, toHashSet

    // 정렬된 컬렉션으로 복사
    toSortedMap, toSortedSet

    // 엔트리를 쌍으로 변환
    toPair

    // 맵을 프로퍼티로 변환
    toProperties
    • Example Code
    // 새로운 복사
    val uIntArray = UIntArray(3) { 1U }
    val toIntArray = uIntArray.toIntArray()
    
    toIntArray[1] = 2
    println(toIntArray.toList())  // [1, 2, 1]
    println(uIntArray.toList())   // [1, 1, 1]

     

     asIntArray()

    원래 값에 대한 참조가 있는 다른 타입으로 변환하는 함수 목록입니다.

    // 배열 타입으로 변환
    asByteArray, asIntArray, asLongArray, asShortArray, asUByteArray, asUIntArray, asULongArray, asUShortArray,

    // 컬렉션 타입으로 변환. list와 sequestion에 대한 비교는 여기서 확인할 수 있습니다.
    asIterable, asList, asSequence

    // 인덱스가 있는 반복자로 변환
    withIndex

    // 사용자가 지정한 기본값을 사용하여 Map으로 변환
    withDefault
    • Example Code
    // 참조 복사
    val uIntArray = UIntArray(3) { 1U }
    val asIntArray = uIntArray.asIntArray()
    
    asIntArray[1] = 2
    
    println(asIntArray.toList())  // [1, 2, 1]
    println(uIntArray.toList())   // [1, 2, 1]

     

    5️⃣ Collection 항목에서 무언가를 생성 ( Conclude )

     

     

    reduce와 fold의 차이 ( 출처 :&nbsp;https://medium.com/mobile-app-development-publication/kotlin-collection-functions-cheat-sheet-975371a96c4b )

     

     📁 Collection과 Sequence의 차이점

    Sequences - Kotlinlang
    Kotlin - Collections와 Sequences의 차이점 - codechacha 
    를 참고하여 작성하였습니다.

    👆 codechacha님 게시글에는 Kotlin Collections와 Java Stream의 차이점, Kotlin에서의 Stream 등추가로 참고하면 좋을 내용이 많이 있습니다.

    Collections조급한 계산법(Eager evalution)으로 동작합니다. "조급한 계산법"이란? 수행해야 할 연산이 있으면 미루지 않고 바로 처리하는 방식을 말합니다.

    Sequences느긋한 계산법(Lazy evaluation)으로 동작합니다. "느긋한 계산법"이란? 가능한 코드의 수행을 미루고, 어쩔 수 없이 연산이 필요한 순간에 연산을 수행하는 방식을 말합니다. 

    따라서, Collections와 Sequences는 동일한 결과 값을 출력할 수 있지만 수행하는 과정이 다릅니다. List 요소의 개수가 매우 적다면 Collections가 빠를 수 있지만, List의 개수가 많다면 Sequences가 성능 측면에서 유리할 수 있습니다.

    • Collections 예제
    val words = "The quick brown fox jumps over the lazy dog".split(" ")
    val lengthsList = words.filter { println("filter: $it"); it.length > 3 }
        .map { println("length: ${it.length}"); it.length }
        .take(4)
    
    println("Lengths of first 4 words longer than 3 chars:")
    println(lengthsList)
    
    /* 결과 값 */
    filter: The
    filter: quick
    filter: brown
    filter: fox
    filter: jumps
    filter: over
    filter: the
    filter: lazy
    filter: dog
    length: 5
    length: 5
    length: 5
    length: 4
    length: 4
    Lengths of first 4 words longer than 3 chars:
    [5, 5, 5, 4]

    위의 코드는 이 다이어그램과 같은 순서로 동작합니다.

    • Sequences 예제
    val words = "The quick brown fox jumps over the lazy dog".split(" ")
    //convert the List to a Sequence
    val wordsSequence = words.asSequence()
    
    val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }
        .map { println("length: ${it.length}"); it.length }
        .take(4)
    
    println("Lengths of first 4 words longer than 3 chars")
    // terminal operation: obtaining the result as a List
    println(lengthsSequence.toList())
    
    /* 결과 값 */
    Lengths of first 4 words longer than 3 chars
    filter: The
    filter: quick
    length: 5
    filter: brown
    length: 5
    filter: fox
    filter: jumps
    length: 5
    filter: over
    length: 4
    [5, 5, 5, 4]

    위의 코드는 이 다이어그램과 같은 순서로 동작합니다.

    take(4)는 4개의 아이템만 가져오면 되기 때문에, 이를 충족하면 이후 아이템에 대해서는 filter()를 수행할 필요가 없습니다. 이러한 부분 때문에, Collections 보다 연산이 빨리 끝날 수 있습니다.

     

    End

    'Kotlin' 카테고리의 다른 글

    [ Kotlin ] 코틀린에서 Queue 사용하기  (0) 2021.12.11
    Comments