scala 如何合并两个元组列表?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13074031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 04:40:18  来源:igfitidea点击:

How to merge two lists of tuples?

listscalamerge

提问by Shakti

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))

回答by paradigmatic

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 l1and l2are the lists of tuples you want merge.

要合并的元组列表在哪里l1l2在哪里。

Now, the breakdown:

现在,细分:

  • (l1 ++ l2)you just concatenate both lists
  • .groupBy( _._1)you group all tuples by their first element. You will receive a Map with the first element as key and lists of tuples starting with this element as values.
  • .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.
  • .toListyou convert the result back to a list.
  • (l1 ++ l2)您只需连接两个列表
  • .groupBy( _._1)您按第一个元素对所有元组进行分组。您将收到一个 Map,其中第一个元素作为键,并以该元素开头的元组列表作为值。
  • .map( kv => (kv._1, kv._2.map( _._2).sum ) )您制作了一个具有相似键的新地图,但值是所有第二个元素的总和。
  • .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

回答by Don Mackenzie

Alternatively you can also use mapValuesto 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.

In this case the function passed to mapValuesreduces each (Char, Int) tuple to just the Int then sums the resulting List of Ints.

在这种情况下,传递给的函数mapValues将每个 (Char, Int) 元组简化为 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 sortedwhich relies on an Ordering[(Char, Int)] implicit instance.

如果输出列表的顺序需要遵循您的示例,只需添加sorted它依赖于 Ordering[(Char, Int)] 隐式实例。

(l1 ::: l2).groupBy(_._1).mapValues(_.map(_._2).sum).toList.sorted

回答by Landei

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.

不幸的是,这不是尾递归。