【问题标题】:How to reverse a Map in Kotlin?如何在 Kotlin 中反转地图?
【发布时间】:2017-07-28 18:36:51
【问题描述】:

我正在尝试在 Kotlin 中反转 Map。到目前为止,我想出了:

mapOf("foo" to 42)
  .toList()
  .map { (k, v) -> v to k }
  .toMap()

在不使用中间人(中间列表)的情况下,有没有更好的方法来做到这一点?

【问题讨论】:

    标签: dictionary kotlin bimap


    【解决方案1】:

    由于MapEntrys 组成,而不是Iterable,您可以改用Map#entries。它将被映射到Map#entrySet 以创建Set<Entry> 的后备视图,例如:

    val reversed = map.entries.associateBy({ it.value }) { it.key }
    

    使用Iterable#associate,这将创建额外的Pairs。

    val reversed = map.entries.associate{(k,v)-> v to k}
    

    使用Map#forEach

    val reversed = mutableMapOf<Int, String>().also {
        //     v-- use `forEach` here     
        map.forEach { (k, v) -> it.put(v, k) } 
    }.toMap()
    // ^--- you can add `toMap()` to create an immutable Map.
    

    【讨论】:

    • 所以要回答“有没有更好的方法可以在不使用中间人(中间人)的情况下做到这一点?”答案是不? :P
    • @aug 是的。我会进一步回答这个问题。
    • 对于最后一个解决方案 "it[v] = k" 比 it.put(v, k) 更加紧凑和富有表现力
    • 如果给定的地图不是 1to1 映射怎么办?如果这些值的区别不足以用作键怎么办?此类操作的输出通常是Map&lt;V, List&lt;K&gt;&gt;,其中K 是键类型,V 是输入映射的值类型。
    【解决方案2】:

    这是一个反转映射的简单扩展函数 - 不会产生不需要的垃圾(如对、中间数据结构和不必要的闭包)

    fun <K, V> Map<K, V>.reversed() = HashMap<V, K>().also { newMap ->
        entries.forEach { newMap.put(it.value, it.key) }
    }
    

    注意apply是内联的,entries.forEach也是内联的(Map::forEach不一样)

    【讨论】:

      【解决方案3】:

      如果您的地图不是 1-1 映射并且您希望反转是值列表:

      mapOf(1 to "AAA", 2 to "BBB", 3 to "BBB").toList()
              .groupBy { pair -> pair.second } // Pair<Int, String>
              .mapValues { entry -> 
                entry.value.map { it.first } // Entry<String, List<Pair<Int, String>>
              }
      
      

      【讨论】:

        【解决方案4】:

        如果您需要将像 m: Map&lt;K, List&lt;V&gt;&gt; 这样的多映射反转为 Map&lt;V, List&lt;K&gt;&gt;,您可以这样做

        m
          .flatMap { it.value.map { oneValue -> oneValue to it.key } }
          .groupBy({ it.first }, { it.second })
          .toMap()
        

        按顺序,

        • mapOf('a' to listOf('b', 'c'), 'd' to listOf('b')) 得到平面映射到类似的序列
        • listOf('b' to 'a', 'c' to 'a', 'b' to 'd') 被分组到
        • listOf('b' to listOf('a', 'd'), 'c' to listOf('a')) 然后转换为地图。

        这可能会创建中间对象。

        【讨论】:

          【解决方案5】:

          我仍在学习 Kotlin 的来龙去脉,但我有相同的要求,从 Kotlin 1.2 开始,您似乎可以迭代 Map,因此 map() 直接像这样:

          @Test
          fun testThatReverseIsInverseOfMap() {
              val intMap = mapOf(1 to "one", 2 to "two", 3 to "three")
              val revMap = intMap.map{(k,v) -> v to k}.toMap()
              assertTrue(intMap.keys.toTypedArray() contentEquals revMap.values.toTypedArray())
              assertTrue(intMap.values.toTypedArray() contentEquals revMap.keys.toTypedArray())
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-01-01
            • 1970-01-01
            • 2020-10-22
            • 2016-09-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多