【问题标题】:Scala reduce Sequence of Map to a Map with max value for each keyScala将Map序列减少为每个键都有最大值的Map
【发布时间】:2020-09-04 18:08:21
【问题描述】:

我有一个这样的地图序列:

Seq(
  Map("k1" -> 1),
  Map("k1" -> 2),
  Map("k2" -> 3),
  Map("k2" -> 4)
)

我想减少到单个地图,其值等于每个 (key,value) 的最大值

预期结果:

Seq(
  Map("k1" -> 2),
  Map("k2" -> 4)
)

如何减少map的序列?

【问题讨论】:

  • 都是单例地图吗?
  • 它们是不可变的地图
  • Map("k1",1) 语法无效。你有元组"k1" -> 1吗?
  • 是的,我很抱歉@MarioGalic
  • 您确定您的预期结果是一系列地图吗?也许你只想要一张地图?另外,你的输入是一个单例映射序列很奇怪,也许你更愿意有一个元组序列?

标签: scala dictionary reduce


【解决方案1】:

2.13 你可以这样做:

def mergeMapsWithMax[K, V : Ordering](data: IterableOnce[Map[K, V]]): Map[K, V] =
  data
    .iterator
    .flatten
    .toList
    .groupMapReduce(_._1)(_._2)(Ordering[V].max)

你可以这样使用:

val data = Seq(
  Map("k1" -> 1),
  Map("k1" -> 2),
  Map("k2" -> 3),
  Map("k2" -> 4)
)
// data: Seq[scala.collection.immutable.Map[String,Int]] = List(Map(k1 -> 1), Map(k1 -> 2), Map(k2 -> 3), Map(k2 -> 4))


mergeMapsWithMax(data)
// res: Map[String,Int] = Map(k1 -> 2, k2 -> 4)

【讨论】:

    【解决方案2】:

    假设您重新考虑使用元组列表而不是映射序列

    val tuples = List(
      ("k1", 1),
      ("k1", 2),
      ("k2", 3),
      ("k2", 4)
    )
    

    像这样尝试foldLeft

    tuples.foldLeft(Map.empty[String, Int]) { case (acc, t @ (key, value)) =>
      acc.get(key) match {
        case Some(oldValue) => if (oldValue >= value) acc else acc + t
        case None => acc + t
      }
    }
    // val res0: Map[String,Int] = Map(k1 -> 2, k2 -> 4)
    

    或使用updatedWith

    tuples.foldLeft(Map.empty[String, Int]) { case (acc, t @ (key, value)) =>
      acc.updatedWith(key) {
        case Some(oldValue) => Some(math.max(oldValue, value))
        case None => Some(value)
      }
    }
    // val res1: Map[String,Int] = Map(k1 -> 2, k2 -> 4)
    

    这应该是performant,因为我们是单次遍历列表,而Map 的查找/添加默认情况下实际上是恒定时间。

    【讨论】:

      【解决方案3】:
      Seq(Map("k1" -> 1), Map("k1" -> 2), Map("k2" -> 3), Map("k2" -> 4))
        .reduce { (m1, m2) =>
          (m1.toSeq ++ m2.toSeq).groupBy(_._1).map {
            case (k, values) => k -> values.map(_._2).max
          }
        }
      

      生产

      Map(k2 -> 4, k1 -> 2)
      

      <script src="https://scastie.scala-lang.org/3aqyPILyRAS1tUagYcpq7w.js"></script>

      【讨论】:

      • 我无法解析值“values.map(_._2).max”上的 .map
      • 这很奇怪。 scastie 代码工作正常。编译器告诉你什么?
      【解决方案4】:

      如果您决定使用映射而不是元组,请使用这个简短(但不一定高效)的版本:

      mapSeq.flatMap(_.toList).groupBy(_._1).map(_._2.max)
      

      否则,你可以使用

      tupleSeq.groupBy(_._1).map(_._2.max)
      

      【讨论】:

        猜你喜欢
        • 2022-11-18
        • 2019-08-29
        • 2019-04-20
        • 2016-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-18
        • 1970-01-01
        相关资源
        最近更新 更多