Scala:按键合并地图

Sub*_*oid 24 maps functional-programming scala scalaz

说我有两张地图:

val a = Map(1 -> "one", 2 -> "two", 3 -> "three")
val b = Map(1 -> "un", 2 -> "deux", 3 -> "trois")
Run Code Online (Sandbox Code Playgroud)

我想通过键合并这些映射,应用一些函数来收集值(在这种特殊情况下,我想将它们收集到一个seq中,给出:

val c = Map(1 -> Seq("one", "un"), 2 -> Seq("two", "deux"), 3 -> Seq("three", "trois"))
Run Code Online (Sandbox Code Playgroud)

感觉应该有一个很好的,惯用的方式来做这个 - 任何建议?如果解决方案涉及scalaz,我很高兴.

Tra*_*own 21

scala.collection.immutable.IntMap有一种intersectionWith方法可以精确地做你想要的(我相信):

import scala.collection.immutable.IntMap

val a = IntMap(1 -> "one", 2 -> "two", 3 -> "three", 4 -> "four")
val b = IntMap(1 -> "un", 2 -> "deux", 3 -> "trois")

val merged = a.intersectionWith(b, (_, av, bv: String) => Seq(av, bv))
Run Code Online (Sandbox Code Playgroud)

这给了你IntMap(1 -> List(one, un), 2 -> List(two, deux), 3 -> List(three, trois)).请注意,它正确地忽略了仅出现的键a.

作为一个方面说明:我经常发现自己想要的unionWith,intersectionWith从等功能Haskell的Data.Map斯卡拉.我认为没有任何原则性的理由,它们只应该IntMap在基础collection.Map特征上,而不是在基本特征中.

  • unionWith,interesectionWith等看起来就像我正在寻找的那样.只是遗憾他们的语言错了! (4认同)

Inf*_*ity 19

val a = Map(1 -> "one", 2 -> "two", 3 -> "three")
val b = Map(1 -> "un", 2 -> "deux", 3 -> "trois")

val c = a.toList ++ b.toList
val d = c.groupBy(_._1).map{case(k, v) => k -> v.map(_._2).toSeq}
//res0: scala.collection.immutable.Map[Int,Seq[java.lang.String]] =
        //Map((2,List(two, deux)), (1,List(one, un), (3,List(three, trois)))
Run Code Online (Sandbox Code Playgroud)

  • 地图是Tuples2的集合.例如:val元组:Tuple3 [Int,Int,String] =(100,10,"one"),如果你想得到一个字符串"one",你可以使用tuple._3.元组很有用,例如,如果您想要返回多个值 (4认同)
  • 而`_._ 1`的第一部分(点之前的下划线)是一个匿名的参数名称.例如:`List(1,2,3,4).map(_.toDouble)`将所有列表成员强制转换为Double.它就像`for(i < - List(1,2,3,4))......`中的`i` (3认同)
  • 这不能正确处理密钥在一个映射中但不在另一个映射中的情况,并且重建映射也使得它比`intersectionWith`更昂贵,它与元素的总数成线性关系. (3认同)

Ben*_*mes 14

Scalaz增加了一个方法|+|的任何类型的A针对其Semigroup[A]可用.

如果您映射地图以使每个值都是单个元素序列,那么您可以非常简单地使用它:

scala> a.mapValues(Seq(_)) |+| b.mapValues(Seq(_))
res3: scala.collection.immutable.Map[Int,Seq[java.lang.String]] = Map(1 -> List(one, un), 2 -> List(two, deux), 3 -> List(three, trois))
Run Code Online (Sandbox Code Playgroud)