[英]How to merge two lists of tuples?
I have two lists in Scala, how to merge them such that the tuples are grouped together? 我在Scala中有两个列表,如何合并它们以便将元组组合在一起?
Is there an existing Scala list API which can do this or need I do it by myself? 是否有现成的Scala列表API可以执行此操作或需要我自己执行此操作?
Input: 输入:
List((a,4), (b,1), (c,1), (d,1))
List((a,1), (b,1), (c,1))
Expected output: 预期产量:
List((a,5),(b,2),(c,2),(d,1))
You can try the following one-line: 您可以尝试以下一行:
scala> ( l1 ++ l2 ).groupBy( _._1 ).map( kv => (kv._1, kv._2.map( _._2).sum ) ).toList
res6: List[(Symbol, Int)] = List(('a,5), ('c,2), ('b,2), ('d,1))
Where l1
and l2
are the lists of tuples you want merge. 其中l1
和l2
是要合并的元组列表。
Now, the breakdown: 现在,细分:
(l1 ++ l2)
you just concatenate both lists (l1 ++ l2)
你只是连接两个列表 .groupBy( _._1)
you group all tuples by their first element. .groupBy( _._1)
您按照第一个元素对所有元组进行分组。 You will receive a Map with the first element as key and lists of tuples starting with this element as values. 您将收到一个Map,第一个元素作为键,以及以此元素作为值开头的元组列表。 .map( kv => (kv._1, kv._2.map( _._2).sum ) )
you make a new map, with similar keys, but the values are the sum of all second elements. .map( kv => (kv._1, kv._2.map( _._2).sum ) )
你制作一个新的地图,使用相似的键,但这些值是所有第二个元素的总和。 .toList
you convert the result back to a list. .toList
将结果转换回列表。 Alternatively, you can use pattern matching to access the tuple elements. 或者,您可以使用模式匹配来访问元组元素。
( l1 ++ l2 ).groupBy( _._1 ).map{
case (key,tuples) => (key, tuples.map( _._2).sum )
}.toList
Alternatively you can also use mapValues
to shorten the code. 或者,您也可以使用mapValues
来缩短代码。
mapValues
, as you can probably guess, allows you to re-map just the value for each (key, value) pair in the Map created by groupBy
. 正如您可能猜到的, mapValues
允许您仅重新映射groupBy
创建的Map中每个(键,值)对的值。
In this case the function passed to mapValues
reduces each (Char, Int) tuple to just the Int then sums the resulting List of Ints. 在这种情况下,传递给mapValues
的函数将每个(Char,Int)元组mapValues
为Int,然后将得到的Int列表相加。
(l1 ::: l2).groupBy(_._1).mapValues(_.map(_._2).sum).toList
If the order of the output list needs to follow your example, just add sorted
which relies on an Ordering[(Char, Int)] implicit instance. 如果输出列表的顺序需要遵循您的示例,则只需添加依赖于Ordering [(Char,Int)]隐式实例的sorted
。
(l1 ::: l2).groupBy(_._1).mapValues(_.map(_._2).sum).toList.sorted
If you can assume that both List[(A,B)]
are ordered according to Ordering[A]
, you could write something like: 如果你可以假设List[(A,B)]
都是按照Ordering[A]
,你可以这样写:
def mergeLists[A,B](one:List[(A,B)], two:List[(A,B)])(op:(B,B)=>B)(implicit ord:Ordering[A]): List[(A,B)] = (one,two) match {
case (xs, Nil) => xs
case (Nil, ys) => ys
case((a,b)::xs,(aa,bb)::ys) =>
if (a == aa) (a, op(b,bb)) :: mergeLists(xs,ys)(op)(ord)
else if (ord.lt(a,aa)) (a, b) :: mergeLists(xs, (aa,bb)::ys)(op)(ord)
else (aa, bb) :: mergeLists((a,b) :: xs, ys)(op)(ord)
}
Unfortunately this isn't tail recursive. 不幸的是,这不是尾递归。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.