【问题标题】:How to merge two maps keeping greater of values for matching keys?如何合并两个地图以保持更大的匹配键值?
【发布时间】:2020-11-11 18:52:44
【问题描述】:

我在 Scala 中有两个可变映射。

val oldMap = Map(10 -> 100, 20 -> 200, 30 -> 300)
val newMap = Map(10 -> 101, 20 -> 200, 30 -> 299, 40 -> 400)

我想将newMap 合并到oldMap 以获得outputMap,如下所示,其中包含两个映射中的所有键,但值大于匹配键的值。

Map(20 -> 200, 40 -> 400, 10 -> 101, 30 -> 300)

我在下面尝试过,它可以工作,但我想知道 scala 的做法。

import scala.collection.mutable.Map

object Test extends App {

  val oldMap = Map(10 -> 100, 20 -> 200, 30 -> 300)
  val newMap = Map(10 -> 101, 20 -> 200, 30 -> 299, 40 -> 400)
  val outputMap = mergeMap(oldMap, newMap)

  println(outputMap)

  def mergeMap(map1: Map[Int, Int], map2: Map[Int, Int]): Map[Int, Int] = {
    val map1Keys = map2.keys
    val itr = map1Keys.iterator
    while (itr.hasNext)
    {
      val id = itr.next
      if (! map1.contains(id)){ // key not present in map1, INSERT
        map1(id) = map2(id)
      }
      else { // key present in map1, UPDATE
        if (map2(id) > map1(id)){
          map1(id) = map2(id)
        }
      }

    }
    map1
  }

  def commonMapKeys[A, B](a: Map[A, B], b: Map[A, B]): scala.collection.Set[A] = a.keySet.intersect(b.keySet)

}

【问题讨论】:

    标签: scala dictionary merge scala-collections


    【解决方案1】:

    您可以将地图变成元组的集合,合并它们,按键分组并选择组中的最大值:

    val oldMap = Map(10 -> 100, 20 -> 200, 30 -> 300)
    val newMap = Map(10 -> 101, 20 -> 200, 30 -> 299, 40 -> 400)
    (oldMap.toSeq ++ newMap.toSeq)
      .groupBy(_._1)
      .mapValues(_.map(_._2).max)
    

    或使用自 Scala 2.13 起可用的 groupMapReduce

    (oldMap.toSeq ++ newMap.toSeq)
        .groupMapReduce(_._1)(_._2)(math.max(_,_))
    

    【讨论】:

      【解决方案2】:
      newMap.foldLeft(oldMap){ case (result, (k, newV)) =>
        val oldV = result.get(k)
        result + (k -> oldV.fold(newV)(newV max _))
      }
      

      您从oldMap 开始,并使用.foldLeft 遍历newMap。在每次迭代中,您从newMap 获取一个键和一个值,并尝试从结果映射(即开头的oldMap)中获取映射到相同键的值。您添加一个从 k 到新值或新旧值的最大值的新映射,以防旧映射也包含 k

      它与您拥有的几乎相同,只是以更实用的方式。

      【讨论】:

      • 这是有效的。你也能解释一下你的答案吗?我对 Scala 编程很陌生。
      • 如果oldMap 中的密钥丢失在新密钥中怎么办?
      • @GuruStron 应该不是问题,如果我做对了。 scastie.scala-lang.org/k85ZBQryRY2UuZA9uRmFyw
      • @conetfun,除了Iterable.foldLeft(),你需要知道Option.fold()(),它定义了一个可选值的映射。当可选项为None 时,它的第一个参数是默认值。如果定义了可选值,则包装在Some() 中的值将传递给第二个参数中的函数。这里的第二个参数newV max _ 是一个函数字面量,_ 代表函数的输入(即展开的oldV
      • 老实说,我没有特别的理由将一个解决方案标记为答案,因为它们都运行良好。我将首先使用@zagyi 解决方案。
      猜你喜欢
      • 1970-01-01
      • 2020-08-31
      • 2016-08-02
      • 2018-02-01
      • 1970-01-01
      • 2017-11-26
      • 1970-01-01
      • 1970-01-01
      • 2022-11-12
      相关资源
      最近更新 更多