Develop!/Kotlin

Map in Kotlin

체리필터 2023. 8. 4. 10:21
728x90
반응형

다른 언어들과 마찬가지로 코틀린도 key, value를 가지고 있는 map을 사용할 수 있다.

fun maps() {
    val constants = mapOf("Pi" to 3.141, "e" to 2.718, "phi" to 1.618)
    println(constants)

    println(constants["e"])
    println(constants.keys)
    println(constants.values)

    var s = ""
    for (entry in constants) {
        s += "${entry.key}=${entry.value}, "
    }
    println(s)

    s = ""
    for ((key, value) in constants) {
        s += "$key=$value, "
    }
    println(s)
}

fun main() {
    maps()
}

map을 생성할 때는 mapOf를 사용할 수 있다. 물론 읽기 전용이다.

map 안에 있는 값을 꺼낼 때는 []를 사용할 수 있으며 키만 전체 다 가져올 때는 keys를, 값만 다 가지고 올 때는 values를 쓰면 된다.

map을 순회 하면서 안에 있는 값을 보고자 할 때는 for문을 사용하면 되며 map entry를 한 개씩 받아 오거나, key, value로 분리해서 받아올 수 있다.

읽기 전용이 아닌 변경 가능한 map을 만들 거라면 mutableMapOf를 사용하면 된다.

fun mutalbeMap() {
    val m = mutableMapOf(5 to "five", 6 to "six")
    println(m)

    m[5] = "5ive"
    println(m[5])

    m += 4 to "four"
    println(m)
}

fun main() {
    mutalbeMap()
}

m[5]의 값을 five 에서 5ive로 바꿨더니 잘 바뀌었다.

그리고 key - 4, value - four 인 entry를 하나 더 추가 했더니 마지막 값으로 잘 들어간 것을 볼 수 있다.

그렇다면 read only인 mapOf로 생성한 map에 값을 추가할 때는 어떻게 되나?

fun readOnlyMap() {
    var m = mapOf(5 to "five", 6 to "six")
    println(m)

    m += (4 to "four")
    println(m)

    m += (3 to "three")
    println(m)
}

위와 같이 코딩 하기 전에 m의 타입을 val로 바꿔서 변경할 수 없게 만들어 두었다면 var로 변경할 것을 intellij에서 제안받게 된다.

var로 바꾸게 되면 이상없이 동작하게 되지만 어떤 방식으로 read only 인 map이 수정 가능하게 된 것일까? 디버그 모드로 확인해 보면 아래와 같다.

처음에 map을 생성 했을 때 주소 값이 779 인 것을 볼 수 있다.

하지만 4를 하나 더 추가 하게 될 경우 entry가 총 3개인 map이긴 하지만 주소값이 792로 바뀐 것을 볼 수 있다. 이것은 기존의 map이 아니라 새로운 map임을 알 수 있다.

3을 하나 더 추가 해 보면 어떨까?

역시나 주소값이 801로 바뀌었다.

read only map을 var로 만든 변수에 할당해서 값을 추가하려다 보니 지금처럼 복사해서 새로운 map을 만들어 내는 방법 밖에 없다.

하지만 위에서 mutableMapOf로 만든 경우는 어떨까? 주소값이 변하는지 확인해 보자.

위에서 볼 수 있듯이 값을 five -> 5ive로 바꾸는 경우이든, entry를 하나 더 추가하는 경우이든 주소값이 779로 고정 되어 있음을 알 수 있다.

map 안에 들어있는 값을 가져오는 방법으로는 key를 바로 호출 하는 방법, getValue or getOrDefault로 불러오는 방법이 있다.

fun getValue() {
    val map = mapOf('a' to "attempt")
    println(map)
    println(map['b'])

    val exception = capture {
        map.getValue('b')
    }
    println(exception)

    val aVal = map.getOrDefault('a', "??")
    val bVal = map.getOrDefault('b', "??")
    println(aVal)
    println(bVal)
}

map 안에 들어있는 것 중에 존재하지 않는 값을 호출하는 경우 단순히 []를 사용하게 되면 null 값을 반환받게 된다.

하지만 getValue를 사용하게 되면 NoSuchElementException을 만나게 된다.

따라서 []를 사용하거나 getOrDefault를 사용해서 값이 없을 경우 기본값을 넣어줄 수 있도록 하는게 좋다.

map의 value에 Object를 넣어줄 수도 있다.

class Concat(val name: String, val phone: String) {
//    override fun toString(): String {
//        return "Concat('$name', '$phone')"
//    }
}

fun objValue() {
    val miffy = Concat("Miffy", "010-111-2222")
    val cleo = Concat("Cleo", "010-333-4444")

    val concats = mapOf(
        miffy.phone to miffy,
        cleo.phone to cleo
    )

    println(concats)
}

위와 같이 값에 Concat object를 넣어준 다음 출력해 보면 다음과 같이 나오게 된다.

Object가 값에 들어가 있기 때문에 key는 전화번호, value는 주소값이 찍히게 된다.

위에서 주석 처리한 toString을 주석 해제하고 다시 실행하게 되면 아래와 같이 보여지게 된다.

 

 

728x90
반응형

'Develop! > Kotlin' 카테고리의 다른 글

확장함수 in kotlin  (0) 2023.08.14
Property in kotlin  (0) 2023.08.07
Set in Kotlin  (0) 2023.08.02
가변인자 목록 in Kotlin  (0) 2023.08.02
list int kotlin  (0) 2023.07.31