List 在Scala中合并两个列表

List 在Scala中合并两个列表,list,scala,pattern-matching,List,Scala,Pattern Matching,从表单的两个列表List[(Int,String): 如果字符串s相同,如何组合整数s以获得第三个列表: l3 = List((4,"a"),(3,"b"),(4,"c")) 现在我正在遍历这两个列表并添加字符串是否相同,但我认为应该有一个简单的模式匹配解决方案 val l = l1 ::: l2 val m = Map[String, Int]() (m /: l) { case (map, (i, s)) => { map.updated(s, i + (map.get(s) g

从表单的两个列表
List[(Int,String)

如果
字符串
s相同,如何组合
整数
s以获得第三个列表:

l3 = List((4,"a"),(3,"b"),(4,"c"))
现在我正在遍历这两个列表并添加字符串是否相同,但我认为应该有一个简单的模式匹配解决方案

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.

但是我认为有一种更优雅的方法来完成
更新的
部分。

请注意,使用此解决方案,列表将被遍历两次

val l3 = (l1 zip l2).foldRight(List[(Int, String)]()) {
  case ((firstPair @ (firstNumber, firstWord),
        secondPair @ (secondNumber, secondWord)),
        result) =>
    if (firstWord == secondWord)
      ((firstNumber + secondNumber), firstWord) :: result
    else
      firstPair :: secondPair :: result
}
那么

(l1 ++ l2).groupBy(_._2).mapValues(_.unzip._1.sum).toList.map(_.swap)
在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))
这是一个快照

import scalaz._
import Scalaz._

val l3 = (l1.map(_.swap).toMap |+| l2.map(_.swap).toMap) toList
|+
方法暴露在所有类型的
T
上,对于这些类型,存在一个
半群[T]
的实现。碰巧的是
Map[String,Int]
的半群正是您想要的。

另一个不透明的两行,效率有问题,但功效无可置疑:

val lst = l1 ++ l2
lst.map(_._2).distinct.map(i => (lst.filter(_._2 == i).map(_._1).sum, i))
for((k,v)使用
Scala 2.13
新方法的替代方法,该方法(顾名思义)相当于
groupBy
,后跟
mapValues
reduce
步骤:

(l1 ::: l2).groupMapReduce(_._2)(_._1)(_ + _).toList.map(_.swap)
// List[(Int, String)] = List((3,b), (4,a), (4,c))
这:

  • l1
    前置到
    l2

  • group
    s基于第二个元组部分的元素(group部分为groupMapReduce)

  • map
    s将分组值映射到它们的第一个元组部分(映射组的一部分mapReduce)

  • reduce
    s值(
    +\uu
    )通过求和(reduce-part-of-groupMapreduce

  • 最后,
    swap
    s元组的部分

这是一个等效版本(适用于group/map/reduce零件),通过以下列表:

(l1 ::: l2).groupBy(_._2).mapValues(_.map(_._1).reduce(_ + _)).toList.map(_.swap)

类似的问题:这只是我的问题,还是当您使用List[(String,Int)]而不是List[(Int,String)]时,这个问题似乎更容易解决?虽然每次我可以在没有换行符的情况下实现一个函数时,我都倾向于拍拍自己的背,但这是相当不透明的!你能给中间产物起一些名字,让它明显地表明它是正确的吗?我建议在REPL上从头到尾处理每个中间结果,然后从(l1++l2)开始(l1++l2).groupBy(u.u 2)…等等。碰巧我有-但我很感兴趣-你真的会在源代码库中留下一行这样的代码,还是会用解释变量名来拆分它?@DuncanMcGregor这是一个非常依赖上下文的问题…可能是,可能不是。分组方式有点混乱…我更喜欢使用
.groupBy(x=>x._2)
,它做同样的事情。
val a = List(1,1,1,0,0,2)
val b = List(1,0,3,2)

scala> List.concat(a,b)
res31: List[Int] = List(1, 1, 1, 0, 0, 2, 1, 0, 3, 2)

(or) 

scala> a.:::(b)
res32: List[Int] = List(1, 0, 3, 2, 1, 1, 1, 0, 0, 2)

(or) 

scala> a ::: b
res28: List[Int] = List(1, 1, 1, 0, 0, 2, 1, 0, 3, 2)
(l1 ::: l2).groupMapReduce(_._2)(_._1)(_ + _).toList.map(_.swap)
// List[(Int, String)] = List((3,b), (4,a), (4,c))
(l1 ::: l2).groupBy(_._2).mapValues(_.map(_._1).reduce(_ + _)).toList.map(_.swap)