Scala 合并两个Map

把Scala的两个Map合并,合并的时候会遇到相同的键和不同的键,

  • 对与相同的键,合并后的值是两个Map的值的和,
  • 对于只存在于一个Map中的键保留其值不变,对于下面两个map的合并
scala> val m1 = Map(1->10, 2->4)
m1: scala.collection.immutable.Map[Int,Int] = Map(1 -> 10, 2 -> 4)

scala> val m2 = Map(2->5, 4->8)
m2: scala.collection.immutable.Map[Int,Int] = Map(2 -> 5, 4 -> 8)

想要的结果:

m3: scala.collection.immutable.Map[Int,Int] = Map(1 -> 10, 2 -> 9, 4 -> 8)

采用scala ++后的结果:

scala> m1 ++ m2
res0: scala.collection.immutable.Map[Int,Int] = Map(1 -> 10, 2 -> 5, 4 -> 8)

这里结果显然不符合预期,我们希望key=2的value是4+5=9,而这里等于5,说明在两个map merge时第二个map的key-value:(2,5)覆盖了第一个map的值(2,4).

1. foreach

此种方法最为简单,就不进行示例。

2. groupBy

scala> val list = m1.toList ++ m2.toList
//list: List[(Int, Int)] = List((1,10), (2,4), (2,5), (4,8))

scala> val merged = list
					.groupBy ( _._1) 
					.map { case (k,v) => k -> v.map(_._2).sum }
//merged: scala.collection.immutable.Map[Int,Int] = Map(2 -> 9, 4 -> 8, 1 -> 10)

此方法先把Map转化成list,然后进行一个groupBy操作,把相同的key聚合到一起,之后进行一个求和。该方法有点是可以处理更多个Map的merge,但缺点也是显而易见的,Map转化为List又转回Map造成了一定开销,并且groupBy代价比较大。

3. foldLeft

scala> val merged = (m1 /: m2) { 
				case (map, (k,v)) =>
        		 map + ( k -> (v + map.getOrElse(k, 0)) )
        		}
//merged: scala.collection.immutable.Map[Int,Int] = 
//Map(1 -> 10, 2 -> 9, 4 -> 8)

这部分代码比较抽象,其中(m1 /: m2) 等价于 m2.foldLeft(m1),可以形象地理解为向左折叠。而foldLeft参数需要接收两个,另外一个参数列表使用case 匹配到一个结果map 和 当前m1中的一个(k,v) pair,这个pair就是foldLeft过程中遍历的每一个值。通过这些操作最终获得我们需要的结果。

4. scalaz

scalaz封装了一个更加优美的二元函数操作符|+|,直接操作两个Map就能得到结果。首先启动scala时附带加入scalaz的包。关于scalaz的说明和下载如下

scala -cp scalaz-core_2.11-7.1.1.jar 

在shell中导入scalaz.Scalaz._就可以使用它的隐式“|+|”操作符来merge我们的两个Map了,非常简洁。

scala> import scalaz.Scalaz._
import scalaz.Scalaz._

scala> m1 |+| m2
res5: scala.collection.immutable.Map[Int,Int] = Map(2 -> 9, 4 -> 8, 1 -> 10)

文章转载来源:http://wangjiachun.github.io/2017/06/26/scala-merge-two-Map/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值