在Scala中组合两个列表

Sam*_*mas 17 scala list pattern-matching

从2个表格列表List[(Int, String):

l1 = List((1,"a"),(3,"b"))
l2 = List((3,"a"),(4,"c"))
Run Code Online (Sandbox Code Playgroud)

如何组合Integers String相同的s来获得第三个列表:

l3 = List((4,"a"),(3,"b"),(4,"c"))
Run Code Online (Sandbox Code Playgroud)

现在我正在遍历两个列表并添加字符串是否相同,但我认为应该有一个简单的模式匹配解决方案.

Deb*_*ski 20

val l = l1 ::: l2
val m = Map[String, Int]()
(m /: l) {
  case (map, (i, s)) => { map.updated(s, i + (map.get(s) getOrElse 0))}
}.toList // Note: Tuples are reversed.
Run Code Online (Sandbox Code Playgroud)

但我认为有更优雅的方式来做这个updated部分.


Mil*_*bin 20

怎么样,

(l1 ++ l2).groupBy(_._2).mapValues(_.unzip._1.sum).toList.map(_.swap)
Run Code Online (Sandbox Code Playgroud)

在REPL上打开一点包装有助于显示正在发生的事情,

scala> l1 ++ l2
res0: List[(Int, java.lang.String)] = List((1,a), (3,b), (3,a), (4,c))

scala> res0.groupBy(_._2)
res1: ... = Map(c -> List((4,c)), a -> List((1,a), (3,a)), b -> List((3,b)))

scala> res1.mapValues(_.unzip)
res2: ... = Map(c -> (List(4),List(c)), a -> (List(1, 3),List(a, a)), b -> (List(3),List(b)))                         

scala> res1.mapValues(_.unzip._1)                                                                                                                                                                      
res3: ... = Map(c -> List(4), a -> List(1, 3), b -> List(3))                                                                                    

scala> res1.mapValues(_.unzip._1.sum)
res4: ... = Map(c -> 4, a -> 4, b -> 3)                                                                                                               

scala> res4.toList                                                                                                                                                                                     
res5: List[(java.lang.String, Int)] = List((c,4), (a,4), (b,3))                                                                                                                                        

scala> res5.map(_.swap)
res6: List[(Int, java.lang.String)] = List((4,c), (4,a), (3,b))
Run Code Online (Sandbox Code Playgroud)

  • 虽然每次我可以在没有换行的情况下实现功能时,我倾向于给自己轻拍一下,这是非常不透明的!你能给中间体一些名称,这些名称会明显表明它是正确的吗? (2认同)

Apo*_*isp 10

使用Scalaz,这很容易.

import scalaz._
import Scalaz._

val l3 = (l1.map(_.swap).toMap |+| l2.map(_.swap).toMap) toList
Run Code Online (Sandbox Code Playgroud)

|+|方法暴露在T存在实现的所有类型上Semigroup[T].事实上,半群Map[String, Int]就是你想要的.