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


92

给出以下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)

有什么建议吗?我想我缺少一种非常简单的方法。

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

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




@VenkatSudheerReddyAedama五天后,我也问过。;-)
pr1001 2015年

Answers:


36

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


谢谢,这很完美!当我进入特定的用例时,我发现列表列表无论如何都会更好,因为我需要映射和减少各种子列表。
09年

2
当然,@ JoshCason在狭义上是“两个以上”。三个确实超过两个。我从“两个以上”的广义上解释这个问题,意思是任意多个。在那种情况下,除非您达到HLists之类,否则就不可能做什么问题都想做。
copumpkin '16

在答案的链接被打破,新的链接是scala-lang.org/api/2.12.1/scala/...
拉梅什Maharjan

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

备查。


32
这对于压缩三个列表非常有用。
感到遗憾的是,该

2
请注意,这首先需要放在一个元组中:zipped不是的函数List
纳撒尼尔·福特

6
zipped在Scala 2.13中已弃用。在2.13中,做l1.lazyZip(l2).lazyZip(l3).toList
赛斯·提苏

30

因此,这段代码无法满足OP的需求,不仅因为这是一个已有四年历史的线程,而且还确实回答了标题问题,也许有人甚至认为它很有用。

要压缩3个收藏夹:

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

做4个集合的样子:as zip bs zip cs zip ds map { case ((a,b),c)} map {case ((a,b),c,d)=>(a,b,c,d)}
詹姆斯·托宾

1
@JamesTobin,您缩短为as zip bs zip cs zip ds map {case (((a,b),c),d)=>(a,b,c,d) }
keepscoding '17年

非常适合各种类型的列表。
FP自由

11

是的,使用zip3


2
谢谢,但仅适用于3个列表。我正在寻找一种解决方案,可以采用N个列表(每个列表包含M个元素)并创建M个TupleN的列表。
pr1001

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

例如:

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

1
这个答案几乎可以解决问题,但是却颠倒了要素。您能否建议一个改进版本,以预期的顺序生成输出?谢谢
fracca 2013年

保留该顺序的修改后的版本: def combineLists[A](ss:List[A]*) = { val sa = ss.reverse; (sa.head.map(List(_)) /: sa.tail)(_.zip(_).map(p=>p._2 :: p._1)) }
rogermenezes,

5

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

最好的选择是为所有22个Tuple尺寸编写zip函数的重载。代码生成器可能会帮助您。


5

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

import scala.{Tuple2 => &}

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

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

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


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

这不适用于任意大小的列表。例如:transpose(List(List(List(“ a”,“ b”),List(“ c”))))
Venkat Sudheer Reddy Aedama 2015年

1
@VenkatSudheerReddyAedama不完整矩阵的换位对我来说没有意义。以您为例,如果c符合ab?您如何表示它与其他产品一致?
Daniel C. Sobral

同意 那是一个不完整的矩阵。我一直在寻找与zipAll相似的东西。就我而言,c是否符合a(即符合索引)?
Venkat Sudheer Reddy Aedama 2015年

2

产品集合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))

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"))((_, _, _, _, _, _, _, _, _, _, _, _))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.