【问题标题】:Kotlin: mutable map of mutable list won't update the listKotlin:可变列表的可变映射不会更新列表
【发布时间】:2021-12-04 23:03:33
【问题描述】:

(这里是 Kotlin 新手)我有一个文本文件,其中的行如下所示:

1-1-1
1-1-2
1-1-3
2-1-1
2-1-2
etc.

我必须将这些数据转换为一个映射,其中键是前 2 个元素,值是与键匹配的第三个元素的列表。比如上面的记录会转化成这个JSON:

1-1: [1, 2, 3]
2-1: [1, 2]
etc.

我无法增加列表。这是一个简化版本,我卡在“其他”上:

fun main () {
    val l1 = mutableListOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")
    val m = mutableMapOf<String, List<Int>>()
    for (e in l1) {
        val c = e.split("-")
        val key = "${c[0]}-${c[1]}"
        if (m[key] == null) m[key] = listOf(c[2].toInt())
        else println("How do I append to the list?")
    }
    println(m)
}

输出:

{1-1=[1], 2-1=[1]}

但我想要:

{1-1=[1, 2, 3], 2-1=[1, 2]}

谢谢(欢迎大家学习惯用形式!)

【问题讨论】:

  • 下面的答案是正确的,但至于你缺少什么:你的List类型切换了,l1应该是只读List(listOf),第二个是map中的值,应该是 MutableList。您可以使用 + 运算符进行附加,当然您也可以使用当前列表执行此操作,但这样做效率低下,因为它会创建一个新列表。

标签: kotlin


【解决方案1】:

如果我们继续遵循您的策略,您需要的是将值类型设为 MutableList。然后,当该键已经存在现有列表时,您可以添加到现有的 MutableList 中:

fun main() {
    val l1 = mutableListOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")
    val m = mutableMapOf<String, MutableList<Int>>()
    for (e in l1) {
        val c = e.split("-")
        val key = "${c[0]}-${c[1]}"
        if (m[key] == null) m[key] = mutableListOf(c[2].toInt())
        else m[key]!!.add(c[2].toInt())
    }
    println(m)
}

使用getOrPut() 会更自然。它返回现有的 MutableList 或创建一个 MutableList 并将其放入地图中(如果缺少)。那么我们就不用处理if/else了,直接把新的item添加到list就可以了。

fun main() {
    val l1 = mutableListOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")
    val m = mutableMapOf<String, MutableList<Int>>()
    for (e in l1) {
        val c = e.split("-")
        val key = "${c[0]}-${c[1]}"
        m.getOrPut(key, ::mutableListOf).add(c[2].toInt())
    }
    println(m)
}

但我们可以使用mapgroupBy 函数更简单地创建它:

val m = l1.map { it.split("-") }
    .groupBy(
        { "${it[0]}-${it[1]}" }, // keys
        { it[2].toInt() } // values
    )

【讨论】:

  • 感谢您的详尽而有教育意义的回复! .groupby 非常漂亮。
【解决方案2】:

您只需调用 Kotlin 标准库的 groupBy 即可获得所需的输出。

val input = listOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")

val result = input.groupBy(
    { it.substringBeforeLast("-") }, // extract key from item
    { it.substringAfterLast("-").toInt() }  // extract value from item
)

第一个 lambda 函数提取每个列表项的分组依据。第二个 lambda 函数提供用于每个列表项的值。

【讨论】:

    【解决方案3】:

    您也可以先将您的值映射到Pairs,然后将它们分组如下:

    fun main(args: Array<String>) {
        val input = listOf("1-1-1", "1-1-2", "1-1-3", "2-1-1", "2-1-2")
    
        val result = input.map {
            val values = it.split("-")
            "${values[0]}-${values[1]}" to values[2]
        }.groupBy ({ it.first }) { it.second }
    
        println(result)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-06
      • 2019-06-13
      • 2021-07-27
      • 2017-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-27
      相关资源
      最近更新 更多