Scala:合并地图

Rob*_*nho 37 merge scala map

如何合并如下地图:

Map1 = Map(1 -> Class1(1), 2 -> Class1(2))
Map2 = Map(2 -> Class2(1), 3 -> Class2(2))
Run Code Online (Sandbox Code Playgroud)

合并后.

Merged = Map( 1 -> List(Class1(1)), 2 -> List(Class1(2), Class2(1)), 3 -> Class2(2))
Run Code Online (Sandbox Code Playgroud)

可以是List,Set或具有size属性的任何其他集合.

dre*_*xin 62

使用标准库,您可以按如下方式执行:

// convert maps to seq, to keep duplicate keys and concat
val merged = Map(1 -> 2).toSeq ++ Map(1 -> 4).toSeq
// merged: Seq[(Int, Int)] = ArrayBuffer((1,2), (1,4))

// group by key
val grouped = merged.groupBy(_._1)
// grouped: scala.collection.immutable.Map[Int,Seq[(Int, Int)]] = Map(1 -> ArrayBuffer((1,2), (1,4)))


// remove key from value set and convert to list
val cleaned = grouped.mapValues(_.map(_._2).toList)
// cleaned: scala.collection.immutable.Map[Int,List[Int]] = Map(1 -> List(2, 4))
Run Code Online (Sandbox Code Playgroud)


tir*_*ran 22

这是我能想到的最简单的实现,

val m1 = Map(1 -> "1", 2 -> "2")
val m2 = Map(2 -> "21", 3 -> "3")

def merge[K, V](m1:Map[K, V], m2:Map[K, V]):Map[K, List[V]] = 
  (m1.keySet ++ m2.keySet) map { i => i -> (m1.get(i).toList ::: m2.get(i).toList) } toMap

merge(m1, m2) // Map(1 -> List(1), 2 -> List(2, 21), 3 -> List(3))
Run Code Online (Sandbox Code Playgroud)

  • 请注意,不计算`m2.keySet`而是将密钥迭代器添加到集合中可能更有效:`m1.keySet ++ m2.keys` (2认同)

sen*_*nia 16

你可以使用scalaz:

import scalaz._, Scalaz._

val m1 = Map('a -> 1, 'b -> 2)
val m2 = Map('b -> 3, 'c -> 4)

m1.mapValues{List(_)} |+| m2.mapValues{List(_)}
// Map('b -> List(2, 3), 'c -> List(4), 'a -> List(1))
Run Code Online (Sandbox Code Playgroud)

您可以使用Set(_)而不是List(_)Sets作为值Map.

半群scalaz小抄(或学习scalaz)有关详细信息|+|运营商.

对于Int |+|作品+,对List-因为++,对于Map它适用|+|于相同的键的值.


Nim*_*007 10

我写了一篇关于此的博客文章,请查看:

http://www.nimrodstech.com/scala-map-merge/

基本上使用scalaz semi group你可以很容易地实现这一点

看起来像是这样的:

  import scalaz.Scalaz._
  Map1 |+| Map2
Run Code Online (Sandbox Code Playgroud)


Dav*_*llo 10

做一个干净的方法:

import cats.implicits._

Map(1 -> "Hello").combine(Map(2 -> "Goodbye"))
//Map(2 -> Goodbye, 1 -> Hello)
Run Code Online (Sandbox Code Playgroud)

重要的是要注意两个地图必须是相同的类型(在这种情况下Map[Int, String]).

很长的解释:

combine并不是Map的真正成员.通过导入cats.implicits,你将带入范围cat的Map内置monoid实例,以及一些启用简洁语法的隐式类.

以上相当于:

Monoid[Map[Int, String]].combine(Map(1 -> "Hello"), Map(2 -> "Goodbye"))
Run Code Online (Sandbox Code Playgroud)

我们使用Monoid"召唤器"函数来获取范围内的Monoid [Map [Int,String]]实例并使用其组合函数.

  • 这并不是真正需要的。这只会被编译,因为 String 有一个默认的 Semigroup 实例,它是串联。因此,如果键相同,则两个字符串会连接起来。因此,如果没有另一种类型的值的 Semigroup 实例,则这将不起作用。 (2认同)

Xav*_*hot 8

开始Scala 2.13,另一个仅基于标准库的解决方案在于使用groupMapwhich (顾名思义)相当于 agroupBy后跟mapValues

// val m1 = Map(1 -> "a", 2 -> "b")
// val m2 = Map(2 -> "c", 3 -> "d")
(m1.toSeq ++ m2).groupMap(_._1)(_._2)
// Map[Int,Seq[String]] = Map(2 -> List("b", "c"), 1 -> List("a"), 3 -> List("d"))
Run Code Online (Sandbox Code Playgroud)

这个:

  • 将两个映射连接为一个元组序列 ( List((1,"a"), (2,"b"), (2,"c"), (3,"d")))。为了简洁,m2隐式转换为Seq适应类型m1.toSeq-但你可以选择,使其明确使用m2.toSeq

  • groups 元素基于它们的第一个元组部分 ( _._1) (Map 的组部分)

  • maps 将值分组到它们的第二个元组部分 ( _._2) (组Map 的映射部分)