如何合并两个元组列表?

Posted

技术标签:

【中文标题】如何合并两个元组列表?【英文标题】:How to merge two lists of tuples? 【发布时间】:2012-10-15 22:59:26 【问题描述】:

我在 Scala 中有两个列表,如何合并它们以使元组组合在一起?

是否有现有的 Scala 列表 API 可以执行此操作或需要我自己执行?

输入:

 List((a,4), (b,1), (c,1), (d,1))
 List((a,1), (b,1), (c,1))

预期输出:

List((a,5),(b,2),(c,2),(d,1))

【问题讨论】:

看来您正在学习“Scala 中的函数式编程原理”课程... @michael.kebe 看起来他们每年都不会改变任务:( Combining two lists in scala 的可能重复项 【参考方案1】:

你可以试试下面一行:

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

其中l1l2 是您要合并的元组列表。

现在,分解:

(l1 ++ l2) 你只是连接两个列表 .groupBy( _._1) 您将所有元组按其第一个元素分组。您将收到一张地图 第一个元素作为键,以该元素开头的元组列表作为值。 .map( kv => (kv._1, kv._2.map( _._2).sum ) ) 你创建了一个新地图,具有相似的键,但值是所有第二个元素的总和。 .toList 您将结果转换回列表。

或者,您可以使用模式匹配来访问元组元素。

( l1 ++ l2 ).groupBy( _._1 ).map
  case (key,tuples) => (key, tuples.map( _._2).sum ) 
.toList

【讨论】:

【参考方案2】:

您也可以使用mapValues 来缩短代码。

mapValues,您可能猜到了,它允许您仅重新映射 groupBy 创建的 Map 中每个(键、值)对的值。

在这种情况下,传递给 mapValues 的函数将每个 (Char, Int) 元组缩减为仅 Int,然后对结果的 Int 列表求和。

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

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

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

【讨论】:

【参考方案3】:

如果你可以假设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)

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

【讨论】:

【参考方案4】:

使用foldLefttoMap

从一个列表中获取地图,然后遍历第二个列表。我们将条目插入到地图中。

l1.foldLeft(l2.toMap)((accumulator, tuple) =>
      accumulator + (tuple._1 -> (accumulator.getOrElse(tuple._1, 0) + tuple._2))
).toList

结果:

List((Symbol(a),5), (Symbol(b),2), (Symbol(c),2), (Symbol(d),1))

说明:

l2.toMapList((a,1), (b,1), (c,1)) 转换为 immutable.Map(a->1, b->1, c->1) foldLeft 遍历 list#1 l1 的每个元组。 将 list1 的(a,4) 添加到生成的地图中,结果为immutable.Map(a->1+4, b->1, c->1) 将list1 的(b,1) 添加到生成的地图中,结果为immutable.Map(a->5, b->2, c->1) 将list1的(c,1)添加到生成的地图中,结果为immutable.Map(a->5, b->2, c->2) 将list1的(d,1)添加到生成的地图中,结果为immutable.Map(a->5, b->2, c->2, d->1) toList 将地图转换回原始输入形式,即List[(Symbol, Int)]

【讨论】:

以上是关于如何合并两个元组列表?的主要内容,如果未能解决你的问题,请参考以下文章

Python面试必考重点之列表,元组和字典第七关——如何将两个列表或元组合并成一个字典

Spark in Python Working with Tuples - 如何在加入两个 RDD 后合并两个元组

如何按两个元素对元组列表进行排序?

如何按行压缩两个元组列表?

python如何合并两个列表?

如何将元组分成两个独立的列表? [重复]