在 Scala 中组合两个列表

发布于 2024-12-07 17:14:34 字数 339 浏览 3 评论 0原文

List[(Int, String) 形式的 2 个列表中:

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

如何将 StringString 相同的 Integer 组合起来获取第三个列表:

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

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

From 2 lists of the form 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:

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

余生共白头 2024-12-14 17:14:34
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.

但我认为有一种更优雅的方法来完成更新部分。

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 updated part.

零度° 2024-12-14 17:14:34

怎么样,

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

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

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,

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))
国粹 2024-12-14 17:14:34

使用 Scalaz,这很容易。

import scalaz._
import Scalaz._

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

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

With Scalaz, this is a snap.

import scalaz._
import Scalaz._

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

The |+| method is exposed on all types T for 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.

温柔戏命师 2024-12-14 17:14:34
for ( (k,v) <- (l1++l2).groupBy(_._2).toList ) yield ( v.map(_._1).sum, k )
for ( (k,v) <- (l1++l2).groupBy(_._2).toList ) yield ( v.map(_._1).sum, k )
南笙 2024-12-14 17:14:34

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

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
}

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
}
叫思念不要吵 2024-12-14 17:14:34

另一个不透明的one双线,其效率值得怀疑,但功效却不容置疑:

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

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))
穿透光 2024-12-14 17:14:34
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)
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)
被翻牌 2024-12-14 17:14:34

使用 Scala 2.13 的新 Miles Sabin 的答案 的替代方案href="https://www.scala-lang.org/api/2.13.x/scala/collection/immutable/List.html#groupMapReduce[K,B](key:A=%3EK)(f:A= %3EB)(reduce:(B,B)=%3EB):scala.collection.immutable.Map[K,B]" rel="nofollow noreferrer">groupMapReduce 方法(如其名称所示)建议)相当于(更有效)的 groupBy,后跟 mapValuesreduce 步骤:

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

此:

  • 前置 l1l2

  • group 元素他们的第二个元组部分(组部分groupMapReduce)

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

  • reduces 值 (_ + _) 通过求和来减少(减少 groupMapReduce 的一部分)

  • 最后交换元组' 部分。

这是等效版本 通过以下列表一次性执行(对于组/映射/减少部分):

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

An alternative to Miles Sabin's answer using Scala 2.13's new groupMapReduce method which is (as its name suggests) an equivalent (more efficient) of a groupBy followed by mapValues and a reduce step:

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

This:

  • prepends l1 to 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.

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

(l1 ::: l2).groupBy(_._2).mapValues(_.map(_._1).reduce(_ + _)).toList.map(_.swap)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文