10

我在 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))
4

4 回答 4

20

您可以尝试以下一行:

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

您要合并的元组列表在哪里l1以及在哪里。l2

现在,细分:

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

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

( l1 ++ l2 ).groupBy( _._1 ).map{
  case (key,tuples) => (key, tuples.map( _._2).sum ) 
}.toList
于 2012-10-25T17:39:28.713 回答
4

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

mapValues,正如您可能猜到的那样,它允许您仅重新映射由groupBy.

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

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

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

(l1 ::: l2).groupBy(_._1).mapValues(_.map(_._2).sum).toList.sorted
于 2012-10-25T23:55:10.383 回答
0

如果您可以假设两者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)
}

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

于 2012-10-26T06:44:35.560 回答
0

使用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.toMap转换List((a,1), (b,1), (c,1))immutable.Map(a->1, b->1, c->1)
  • foldLeft遍历 list#1 的每个元组l1
    • (a,4)的 list1 被添加到生成的地图中,导致immutable.Map(a->1+4, b->1, c->1)
    • (b,1)的 list1 被添加到生成的地图中,导致immutable.Map(a->5, b->2, c->1)
    • (c,1)的 list1 被添加到生成的地图中,导致immutable.Map(a->5, b->2, c->2)
    • (d,1)的 list1 被添加到生成的地图中,导致immutable.Map(a->5, b->2, c->2, d->1)
  • toList将地图转换回原始输入形式,即List[(Symbol, Int)]
于 2021-09-21T09:53:53.177 回答