Kotlin-将项目添加到Map中的列表的惯用方法

dsf9zpds  于 2022-11-25  发布在  Kotlin
关注(0)|答案(5)|浏览(156)

我有一个MutableMap<String, MutableList<String>,我正在向其中添加项,基本上是一个集合,其中同一个键与多个值相关联。
每当我想添加一个新值时,我需要首先检查是否已经有一个列表与同一个键相关联,如果没有则初始化一个,然后将值添加到列表中。
我可以用一种非常详细的方式来完成这个过程

if (map.containsKey(key)) {
    map[key].add(value)
} else {
    map[key] = mutableListOf(value)
}

我也可以用一种非常简洁的方式来完成

map[key] = (map[key] ?: mutableListOf()) + mutableListOf(value)).toMutableList()

在其他几个方面,在冗长与简洁之间。
不过,在Kotlin,这种习惯做法是什么呢?
我的目标并不是简洁,而是一种可以立即识别和理解的形式。

efzxgjgh

efzxgjgh1#

您可以使用getOrPut

map.getOrPut(key) { mutableListOf() }.add(value)
du7egjpx

du7egjpx2#

我不得不考虑Python,因为它提供了一个defaultdict,可以像这样使用:

from collections import defaultdict 

data = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 5)]
d = defaultdict(set)
for k, v in data:
    d[k].add(v)

print(d.items()) # dict_items([('red', {1, 3}), ('blue', {2, 4, 5})])

有趣的是,Kotlin也有类似的内置扩展,即withDefault扩展:

val data = listOf("red" to 1, "blue" to 2, "red" to 3, "blue" to 4, "red" to 1, "blue" to 5)
val map = mutableMapOf<String, Set<Int>>().withDefault { emptySet() }
for (d in data) {
    map[d.first] = (map.getValue(d.first) + d.second)
}
jvidinwx

jvidinwx3#

创建一个扩展函数(命名为“可立即识别和理解”的函数):

fun MutableMap<String, MutableList<String>>.addValue(key: String, value: String) {
    if (containsKey(key)) {
        this[key]?.add(value)
    } else {
        this[key] = mutableListOf(value)
    }
}

在需要时使用扩展功能:

map.addValue(key, value)
zbsbpyhn

zbsbpyhn4#

这是所提供的答案@Xid的通用版本,无论键和值的类型如何,都可以使用

fun <K, V> MutableMap<K, MutableList<V>>.addValue(key: K, value: V) {
    if (containsKey(key)) {
        this[key]?.add(value)
    } else {
        this[key] = mutableListOf(value)
    }
}
kgsdhlau

kgsdhlau5#

其他答案也可以,但它们都是针对使用MutableList作为值的,对我来说不够简洁,这里有一个与python的defaultdict完全相似的解决方案。
定义这个类(不是KotlinMaven,所以欢迎改进):

class defaultMutableMapOf<T, U>(
  private val map: MutableMap<T, U> = mutableMapOf(),
  private val defaultValue: () -> U,
) : MutableMap<T, U> by map {
  override fun get(key: T): U = if (key in map) {
      map[key]!!
  } else {
      map[key] = defaultValue.invoke()
      map[key]!!
  }
}

用法:

val map1 = defaultMutableMapOf<String, Int> { 0 }

  map1["hello"]++
  map1["world"] += 2
  // map1 = {"hello":1,"world":2}

  val map2 = defaultMutableMapOf<String, MutableList<String>> { mutableListOf() }

  map2["categories"].addAll(listOf("A", "B", "C"))
  map2["items"] += "item1"
  // map2 = {"categories":["A","B","C"],"items":["item1"]}

我不知道为什么Kotlin没有这样的默认设置

相关问题