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

时间:2009-11-02 23:49:49

标签: scala functional-programming list zip

给出以下Scala列表:

val l = List(List("a1", "b1", "c1"), List("a2", "b2", "c2"), List("a3", "b3", "c3"))

我怎样才能得到:

List(("a1", "a2", "a3"), ("b1", "b2", "b3"), ("c1", "c2", "c3"))

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

任何建议如何做到这一点?我想我错过了一种非常简单的方法。

更新:我正在寻找一种解决方案,可以获取每个包含M个元素的N个列表列表,并创建一个M个元组列表。

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

11 个答案:

答案 0 :(得分:199)

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

供将来参考。

答案 1 :(得分:31)

我不相信可以生成任意大小的元组列表,但如果您不介意获取列表列表,则transpose function完全符合您的要求。

答案 2 :(得分:26)

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

要压缩3个集合:

as zip bs zip cs map { 
  case ((a,b), c) => (a,b,c)
}

答案 3 :(得分:12)

是的,zip3

答案 4 :(得分:5)

Scala将其所有不同的元组大小视为不同的类(Tuple1Tuple2Tuple3Tuple4,...,Tuple22)它们都是从Product特征继承的,如果它们都可以由同一个函数返回,那么特征没有足够的信息来实际使用来自不同大小的元组的数据值。 (scala的泛型也不足以处理这种情况。)

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

答案 5 :(得分: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))
}

答案 6 :(得分:5)

transpose可以解决问题。一种可能的算法是:

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

例如:

combineLists(List(1, 2, 3), List(10,20), List(100, 200, 300))
// => List[List[Int]] = List(List(1, 10, 100), List(2, 20, 200))

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

combineLists(List(1, 2, 3), List(10,20))
// => List[List[Int]] = List(List(1, 10), List(2, 20))

答案 7 :(得分:5)

如果你不想下去应用scalaz / cats /(在这里插入你喜欢的函数库)路由,模式匹配是要走的路,尽管(_, _)语法有点尴尬嵌套,所以让我们改变它:

import scala.{Tuple2 => &}

for (i1 & i2 & i3 & i4 <- list1 zip list2 zip list3 zip list4) yield (i1, i2, i3, i4)

&在这里是一个随意的选择,任何看起来很好的中缀都应该这样做。但是,在代码审查期间,您可能会得到一些眉毛。

它也适用于您可以zip(例如Future s)

的任何内容

答案 8 :(得分:2)

product-collections有一个flatZip操作,直到22岁。

scala> List(1,2,3) flatZip Seq("a","b","c") flatZip Vector(1.0,2.0,3.0) flatZip Seq(9,8,7)
res1: com.github.marklister.collections.immutable.CollSeq4[Int,String,Double,Int] = 
CollSeq((1,a,1.0,9),
        (2,b,2.0,8),
        (3,c,3.0,7))

答案 9 :(得分:1)

Scala 2.12.13 及以下

如果你知道输入的List有多长,你可以将列表加入一个Tuple,使用Tuple的.zipped方法:

val l = List(List("a1", "b1", "c1"), List("a2", "b2", "c2"), List("a3", "b3", "c3"))

println(l match {
  case l1::l2::l3::_ => (l1,l2,l3).zipped.toList
  case _ => throw new IllegalArgumentException("List is not the right length")
}) // List((a1,a2,a3), (b1,b2,b3), (c1,c2,c3))

Scastie Example - 2.12.13

>= Scala 2.13

不推荐使用上述解决方案 - 使用lazyZip 代替:

val l = List(List("a1", "b1", "c1"), List("a2", "b2", "c2"), List("a3", "b3", "c3"))

println(l match {
  case l1::l2::l3::_ => (l1 lazyZip l2 lazyZip l3).toList
  case _ => throw new IllegalArgumentException("List is not the right length")
}) // List((a1,a2,a3), (b1,b2,b3), (c1,c2,c3))

Scastie Example - 2.13.0

答案 10 :(得分:0)

使用Scalaz:

import scalaz.Zip
import scalaz.std.list._

// Zip 3
Zip[List].ap.tuple3(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"))

// Zip 4
Zip[List].ap.tuple4(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"))

// Zip 5
Zip[List].ap.tuple5(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"),
                    List("a5", "b5"))

超过5:

// Zip 6
Zip[List].ap.apply6(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"),
                    List("a5", "b5"),
                    List("a6", "b6"))((_, _, _, _, _, _))

// Zip 7
Zip[List].ap.apply7(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"),
                    List("a5", "b5"),
                    List("a6", "b6"),
                    List("a7", "b7"))((_, _, _, _, _, _, _))

...

// Zip 12
Zip[List].ap.apply12(List("a1", "b1"),
                     List("a2", "b2"),
                     List("a3", "b3"),
                     List("a4", "b4"),
                     List("a5", "b5"),
                     List("a6", "b6"),
                     List("a7", "b7"),
                     List("a8", "b8"),
                     List("a9", "b9"),
                     List("a10", "b10"),
                     List("a11", "b11"),
                     List("a12", "b12"))((_, _, _, _, _, _, _, _, _, _, _, _))