list 在 Scala 中组合两个列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7621705/
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-09-11 01:43:38  来源:igfitidea点击:

Combining two lists in Scala

listscalapattern-matching

提问by Samuel Thomas

From 2 lists of the form List[(Int, String):

从表格的 2 个列表中List[(Int, String)

l1 = List((1,"a"),(3,"b"))
l2 = List((3,"a"),(4,"c"))

how can I combine the Integers where the Strings are the same to get this third list:

我如何组合IntegersString相同的s 以获得第三个列表:

l3 = List((4,"a"),(3,"b"),(4,"c"))

Right now I'm traversing both of the lists and adding if the strings are the same, but I think there should be a simple solution with pattern matching.

现在我正在遍历两个列表并添加字符串是否相同,但我认为应该有一个简单的模式匹配解决方案。

回答by Debilski

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.

But I suppose there is a more elegant way to do the updatedpart.

但我想有一种更优雅的方式来完成这个updated部分。

回答by Miles Sabin

How about,

怎么样,

(l1 ++ l2).groupBy(_._2).mapValues(_.unzip._1.sum).toList.map(_.swap)

Unpacking this a little on the REPL helps to show what's going on,

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

回答by Apocalisp

With Scalaz, this is a snap.

使用Scalaz,这很容易。

import scalaz._
import Scalaz._

val l3 = (l1.map(_.swap).toMap |+| l2.map(_.swap).toMap) toList

The |+|method is exposed on all types Tfor which there exists an implementation of Semigroup[T]. And it just so happens that the semigroup for Map[String, Int]is exactly what you want.

|+|方法在所有T存在 的实现的类型上公开Semigroup[T]。碰巧的是,用于的半群Map[String, Int]正是您想要的。

回答by AmigoNico

for ( (k,v) <- (l1++l2).groupBy(_._2).toList ) yield ( v.map(_._1).sum, k )

回答by KARTHIKEYAN.A

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)

回答by Xavier Guihot

An alternative to Miles Sabin's answerusing Scala 2.13's new groupMapReducemethod which is (as its name suggests) an equivalent (more efficient) of a groupByfollowed by mapValuesand a reducestep:

可替换数萨宾的回答使用Scala 2.13的新groupMapReduce方法,它是(顾名思义)的等效(更有效)groupBy,随后mapValues与一个reduce步骤:

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

This:

这个:

  • prepends l1to l2

  • groups elements based on their second tuple part (group part of groupMapReduce)

  • maps grouped values to their first tuple part (map part of groupMapReduce)

  • reduces values (_ + _) by summing them (reduce part of groupMapReduce)

  • and finally swaps tuples' parts.

  • l1置于l2

  • groups 元素基于它们的第二个元组部分(MapReduce 的组部分)

  • maps 将值分组到它们的第一个元组部分(组MapReduce 的映射部分)

  • reduces 值 ( _ + _) 通过对它们求和(减少 groupMap Reduce 的一部分)

  • 最后swap是元组的部分。

This is an equivalent version performed in one pass(for the group/map/reduce part) through the List of:

这是通过以下列表在一次传递中执行的等效版本(对于 group/map/reduce 部分):

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

回答by Luigi Plinge

Another opaque onetwo-liner of questionable efficiency yet indubitable efficacy:

另一种不透明的一个可疑的效率,但不容置疑的功效两班轮:

val lst = l1 ++ l2
lst.map(_._2).distinct.map(i => (lst.filter(_._2 == i).map(_._1).sum, i))

回答by agilesteel

Note that with this solution, the lists are traversed twice.

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

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
}