guenhter
guenhter

Reputation: 12177

Idiomatic way to add an element into sub-list in full-immutable hierarchy

I have the following data-structure:

var foo: Map<String, List<String>> = emptyMap()
foo += mapOf(
        "1" to listOf("a", "b"),
        "2" to listOf("a", "b"),
        "3" to listOf("a", "b")
)

Map and sub-list are both immutable. I now want to add the element c to the list of the first element in the map.

I came up with this solutions:

foo += "1" to (foo["1"] ?: emptyList()) + "c"

but is this really the idiomatic way?


Update based on @hotkeys answer

foo += "1" to foo["1"].orEmpty() + "c"

Upvotes: 2

Views: 74

Answers (2)

JTeam
JTeam

Reputation: 1505

The declaration and assignment can be joined unless there is some problem. Make map & list mutable, as the need is to mutate

var foo: MutableMap<String, MutableList<String>> = mutableMapOf(
        "1" to mutableListOf("a", "b"),
        "2" to mutableListOf("a", "b"),
        "3" to mutableListOf("a", "b")
)

we can use when block like below,

when {
    foo.containsKey("1") -> foo["1"]?.add("c")
    else -> foo["1"] = mutableListOf("c")

}

Upvotes: 0

hotkey
hotkey

Reputation: 148001

One alternative you could check is the approach that the incubating library kotlinx.collections.immutable uses (or just use that library). It allows you to .mutate { ... } a map, which creates an immutable copy of that map with the applied mutations:

val m = immutableHashMapOf("1" to listOf("a", "b"))

val result = m.mutate { it["1"] = it["1"].orEmpty() + "c" }

See also: .orEmpty()

There's no equivalent to .mutate { ... } in the standard library, though, but you can define your own extension for read-only Map that would do the same.

Upvotes: 1

Related Questions