Scala将Sequence of Map缩减为一个Map,每个键都有最大的值。

问题描述 投票:0回答:1

我有一个Seq of Map是这样的。

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

我想把它还原成一个单一的Map,它的值等于每个Map的最大值。(key,value)

预期的结果。

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

如何减少地图的序列?

scala dictionary reduce
1个回答
2
投票

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)

这应该是相当 表演者 因为我们是单次通过的,而且是通过列表和 Map的lookupadd默认具有有效的恒定时间。


1
投票
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>

0
投票

如果你决定使用地图而不是元组,请使用这个简短(但不一定有效)的版本。

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

否则,你可以使用

tupleSeq.groupBy(_._1).map(_._2.max)
© www.soinside.com 2019 - 2024. All rights reserved.