我可以在Scala中一起压缩两个以上的列表吗?

pr1*_*001 88 zip functional-programming scala list

给出以下Scala列表:

val l = List(List("a1", "b1", "c1"), List("a2", "b2", "c2"), List("a3", "b3", "c3"))
Run Code Online (Sandbox Code Playgroud)

我怎样才能得到:

List(("a1", "a2", "a3"), ("b1", "b2", "b3"), ("c1", "c2", "c3"))
Run Code Online (Sandbox Code Playgroud)

由于zip只能用于组合两个列表,我认为你需要以某种方式迭代/减少主列表.毫不奇怪,以下不起作用:

scala> l reduceLeft ((a, b) => a zip b)
<console>:6: error: type mismatch;
 found   : List[(String, String)]
 required: List[String]
       l reduceLeft ((a, b) => a zip b)
Run Code Online (Sandbox Code Playgroud)

有任何建议,如何做到这一点?我想我错过了一个非常简单的方法.

更新:我正在寻找一个解决方案,可以采用N个列表列表,每个列表包含M个元素,并创建M个元组列表.

更新2:事实证明,对于我的特定用例来说,最好有一个列表列表,而不是元组列表,所以我接受南瓜的回应.它也是最简单的,因为它使用本机方法.

Xor*_*lev 204

scala> (List(1,2,3),List(4,5,6),List(7,8,9)).zipped.toList
res0: List[(Int, Int, Int)] = List((1,4,7), (2,5,8), (3,6,9))
Run Code Online (Sandbox Code Playgroud)

备查.

  • 这对于压缩三个列表非常有用.耻辱这不适用于超过三个列表:( (31认同)
  • Scala 2.13 中已弃用“zipped”。在 2.13 中,执行 `l1.lazyZip(l2).lazyZip(l3).toList` (10认同)
  • 请注意,这首先需要在元组中:`zipped`不是`List`的函数. (2认同)

cop*_*kin 34

我不相信它可以生成任意大小的元组列表,但如果您不介意获取列表列表,则转置函数可以完全满足您的需要.

  • @JoshCason在最狭义的"两个以上"中,当然.三个确实超过两个.我从更广泛的意义上解释了这个问题"两个以上",意思是任意多个.在这种情况下,除非你找到'HList`s之类的东西,否则不可能做出问题所需. (2认同)

Bij*_*lle 29

所以这段代码不会满足OP的需求,不仅因为这是一个有四年历史的线程,而且它确实回答了标题问题,也许有人甚至可能觉得它很有用.

要压缩3个集合:

as zip bs zip cs map { 
  case ((a,b), c) => (a,b,c)
}
Run Code Online (Sandbox Code Playgroud)


Har*_*d L 11

是的,有了zip3.

  • 谢谢,但它只适用于3个列表.我正在寻找一个解决方案,可以采用每个M元素的N列表列表,并创建一个M元组列表. (2认同)

W.P*_*ill 6

transpose诀窍.一种可能的算法是:

def combineLists[A](ss:List[A]*) = {
    val sa = ss.reverse;
    (sa.head.map(List(_)) /: sa.tail)(_.zip(_).map(p=>p._2 :: p._1))
}
Run Code Online (Sandbox Code Playgroud)

例如:

combineLists(List(1, 2, 3), List(10,20), List(100, 200, 300))
// => List[List[Int]] = List(List(1, 10, 100), List(2, 20, 200))
Run Code Online (Sandbox Code Playgroud)

答案被截断为输入中最短列表的大小.

combineLists(List(1, 2, 3), List(10,20))
// => List[List[Int]] = List(List(1, 10), List(2, 20))
Run Code Online (Sandbox Code Playgroud)


Ken*_*oom 5

斯卡拉把所有的不同字段大小的不同类别(Tuple1,Tuple2,Tuple3,Tuple4,... Tuple22),而他们做了一切从继承Product特质,即特质没有携带足够的信息,实际上是从不同大小的元组使用的数据值如果它们都可以由同一个函数返回.(scala的泛型也不足以处理这种情况.)

最好的办法是为所有22个元组大小编写zip函数的重载.代码生成器可能会帮助您解决此问题.


Dan*_*ral 5

我不相信这是可能的而不是重复.原因很简单:您无法定义要求的函数的返回类型.

例如,如果您的输入是List(List(1,2),List(3,4)),那么返回类型将是List [Tuple2 [Int]].如果它有三个元素,则返回类型为List [Tuple3 [Int]],依此类推.

您可以返回List [AnyRef],甚至List [Product],然后制作一堆案例,每个条件一个.

对于一般的List转置,这适用:

def transpose[T](l: List[List[T]]): List[List[T]] = l match {
  case Nil => Nil
  case Nil :: _ => Nil
  case _ => (l map (_.head)) :: transpose(l map (_.tail))
}
Run Code Online (Sandbox Code Playgroud)


小智 5

如果您不想沿用适用的scalaz / cats /(在此处插入您喜欢的功能库)路线,则模式匹配是解决问题的方法,尽管(_, _)语法在嵌套方面有点尴尬,所以让我们对其进行更改:

import scala.{Tuple2 => &}

for (i1 & i2 & i3 & i4 <- list1 zip list2 zip list3 zip list4) yield (i1, i2, i3, i4)
Run Code Online (Sandbox Code Playgroud)

这里&是一个任意选择,任何看起来不错的infix都应该这样做。不过,在代码审查期间,您可能会大惊小怪。

它也应该可以使用任何可能的方法zip(例如Futures)