[Kotlin] Collection

Hood·2024년 8월 27일

Kotlin

목록 보기
5/18
post-thumbnail

✍ 코틀린과 친해지자

PS 문제를 하나씩 풀다 보니, 공부가 필요하다고 느낀 문법을 정리한 글입니다.


🔎 Collection

Kotlin의 Collection은 여러 데이터를 편하게 다루기 위해 제공되는 컬렉션 라이브러리입니다.
여러 요소를 하나의 그룹으로 묶어서 관리할 수 있도록 도와주며,
요소 조회, 반복, 포함 여부 확인 같은 공통 작업을 수행할 수 있는 인터페이스를 제공합니다.

Kotlin 컬렉션은 크게 읽기 전용 컬렉션변경 가능한 컬렉션으로 나뉩니다.

  • 읽기 전용 컬렉션은 요소를 조회하고 반복하는 기능을 제공합니다.
  • 변경 가능한 컬렉션은 여기에 더해 요소 추가, 삭제, 수정 같은 작업도 지원합니다.

예를 들어 Collection<T>는 읽기 전용 컬렉션의 기본 인터페이스이고,
MutableCollection<T>는 여기에 쓰기 기능을 추가한 인터페이스입니다.

fun printAll(strings: Collection<String>) {
    for (s in strings) print("$s ")
    println()
}

fun main() {
    val stringList = listOf("one", "two", "one")
    printAll(stringList)

    val stringSet = setOf("one", "two", "three")
    printAll(stringSet)
}

위 예시는 Collection<T>가 컬렉션의 공통 동작을 제공한다는 점을 보여줍니다.
리스트와 셋은 서로 다른 자료구조이지만, 둘 다 Collection의 형태로 다룰 수 있기 때문에
같은 함수에 전달하여 사용할 수 있습니다.

또한 컬렉션은 Iterable<T>를 상속하므로 for 문으로 순회할 수 있고,
MutableCollection<T>add, remove처럼 값을 변경하는 작업도 가능합니다.


Collection 종류

1. List

List순서가 있는 컬렉션입니다.
각 요소는 인덱스(위치를 나타내는 정수)로 접근할 수 있으며, 같은 값이 여러 번 들어갈 수도 있습니다.

즉, List는 다음과 같은 특징을 가집니다.

  • 순서가 중요합니다.
  • 중복을 허용합니다.
  • 인덱스는 0부터 시작합니다.
fun main() {
    val numbers = listOf("one", "two", "three", "four")
    println("리스트 크기 : ${numbers.size}")
    println("세 번째 요소 : ${numbers.get(2)}")
    println("네 번째 요소 : ${numbers[3]}")
    println("\"two\"의 인덱스는? ${numbers.indexOf("two")}")
}

위 예제를 보면 인덱스가 0부터 시작하기 때문에
세 번째 요소를 가져오려면 2를 사용해야 한다는 것을 알 수 있습니다.
또한 size는 현재 리스트에 들어 있는 전체 요소 개수를 반환합니다.

data class Person(var name: String, var age: Int)

fun main() {
    val bob = Person("Bob", 31)
    val people1 = listOf(Person("Adam", 28), bob, bob)
    val people2 = listOf(Person("Adam", 28), Person("Bob", 31), bob)

    println(people1 == people2)
    bob.age = 32
    println(people1 == people2)
}

이 예제는 List순서와 각 위치의 값을 기준으로 비교된다는 점을 보여줍니다.
리스트는 같은 객체를 여러 번 담을 수 있으므로 중복도 허용됩니다.

그리고 people1 == people2는 단순히 참조가 같은지를 보는 것이 아니라,
각 위치의 요소가 구조적으로 같은지를 비교합니다.
따라서 리스트에서는 무엇이 들어 있는지뿐 아니라 어떤 순서로 들어 있는지도 중요합니다.


2. Set

Set중복을 허용하지 않는 컬렉션입니다.
수학에서의 집합과 비슷하게, 같은 값은 한 번만 저장됩니다.

즉, Set의 특징은 다음과 같습니다.

  • 중복을 허용하지 않습니다.
  • 요소의 포함 여부를 확인할 때 유용합니다.
  • 일반적으로 동등성 비교에서는 순서가 중요하지 않습니다.
fun main() {
    val numbers = setOf(1, 2, 3, 4)
    println("요소 개수: ${numbers.size}")

    if (numbers.contains(1)) {
        println("1은 set 안에 포함되어 있습니다.")
    }

    val numbersBackwards = setOf(4, 3, 2, 1)
    println("두 set가 같은가? : ${numbers == numbersBackwards}")
}

Set<T>는 고유한 요소만 저장하기 때문에,
순서가 다르더라도 같은 요소를 가지고 있다면 같은 집합으로 판단됩니다.
그래서 위 예제에서는 true가 출력됩니다.

println(numbers.first() == numbersBackwards.first())
println(numbers.first() == numbersBackwards.last())

다만 여기서는 한 가지 주의할 점이 있습니다.
Set동등성 비교는 순서를 보지 않지만, first()last()순회 순서의 영향을 받습니다.

즉, numbers == numbersBackwardstrue일 수 있지만,
first()last()의 결과는 실제 저장 순서나 구현 방식에 따라 달라질 수 있습니다.
그래서 Set에서는 같은 요소를 가지고 있는가어떤 순서로 순회되는가를 구분해서 봐야 합니다.


3. Map

Map키(key)와 값(value)의 쌍으로 이루어진 컬렉션입니다.
각 키는 고유해야 하며, 하나의 키는 하나의 값에 대응됩니다.

즉, Map의 특징은 다음과 같습니다.

  • 키는 중복될 수 없습니다.
  • 값은 중복될 수 있습니다.
  • 특정 키를 통해 값을 빠르게 찾을 수 있습니다.
fun main() {
    val numbersMap = mapOf(
        "key1" to 1,
        "key2" to 2,
        "key3" to 3,
        "key4" to 1
    )

    println("모든 키들 : ${numbersMap.keys}")
    println("모든 값들 : ${numbersMap.values}")

    if ("key2" in numbersMap) {
        println("key2의 값은? ${numbersMap["key2"]}")
    }

    if (1 in numbersMap.values) {
        println("값 1은 map 안에 있습니다!")
    }

    if (numbersMap.containsValue(1)) {
        println("값 1은 map 안에 있습니다!")
    }
}

위 예제를 보면 key1key4의 값이 모두 1인 것을 확인할 수 있습니다.
즉, 키는 고유해야 하지만 값은 중복될 수 있습니다.

또한 Map은 특정 키에 대응하는 값을 조회하는 데 적합하기 때문에,
예를 들어 직원 ID와 직원 정보, 상품 코드와 가격처럼
서로 연결된 데이터를 다룰 때 유용합니다.

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)
val anotherMap = mapOf("key2" to 2, "key1" to 1, "key4" to 1, "key3" to 3)

println("두 맵들은 같은가? : ${numbersMap == anotherMap}")

위 예제를 보면 키와 값은 같지만 입력한 순서가 다릅니다.
그럼에도 true가 출력되는 이유는 Map의 동등성 비교가
키-값 쌍이 같은지를 기준으로 하기 때문입니다.
즉, Map 역시 비교 자체에서는 순서가 중요하지 않습니다.

fun main() {
    val numbersMap = mutableMapOf("one" to 1, "two" to 2)
    numbersMap.put("three", 3)
    numbersMap["one"] = 11

    println(numbersMap)
}

위 예제는 mutableMapOf를 사용하여 수정 가능한 Map을 만드는 예제입니다.
put()으로 새로운 키-값 쌍을 추가할 수 있고,
이미 존재하는 키에 새로운 값을 넣으면 기존 값이 변경됩니다.


📌 결론

이번 글에서는 Kotlin의 Collection에 대해 정리해보았습니다.
프로그램에서는 단순한 변수 하나만 다루는 경우보다, 여러 값을 묶어서 관리해야 하는 경우가 훨씬 많습니다.
이때 List, Set, Map 같은 컬렉션을 상황에 맞게 선택하면 데이터를 더 효율적으로 다룰 수 있습니다.

  • List는 순서가 중요하고 중복을 허용할 때
  • Set은 중복 없는 데이터 묶음이 필요할 때
  • Map은 키와 값을 연결해서 관리하고 싶을 때

다음 글에서는 이러한 Collection을 실제로 다룰 때 자주 사용하는 함수들도 함께 정리해보려고 합니다.

참고

profile
달을 향해 쏴라, 빗나가도 별이 될 테니 👊

0개의 댓글