views:

511

answers:

4

Given the following Scala List:

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

How can I get:

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

Since zip can only be used to combine two Lists, I think you would need to iterate/reduce the main List somehow. Not surprisingly, the following doesn't work:

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)

Any suggestions one how to do this? I think I'm missing a very simple way to do it.

Update: I'm looking for a solution that can take a List of N Lists with M elements each and create a List of M TupleNs.

Update 2: As it turns out it is better for my specific use-case to have a list of lists, rather than a list of tuples, so I am accepting pumpkin's response. It is also the simplest, as it uses a native method.

+6  A: 

Yes, with zip3.

Harold L
Thanks, but it only works with 3 lists. I'm looking for a solution that can take a List of N Lists with M elements each and create a List of M TupleNs.
pr1001
+4  A: 

Scala treats all of its different tuple sizes as different classes (Tuple1, Tuple2, Tuple3, Tuple4,...,Tuple22) while they do all inherit from the Product trait, that trait doesn't carry enough information to actually use the data values from the different sizes of tuples if they could all be returned by the same function. (And scala's generics aren't powerful enough to handle this case either.)

Your best bet is to write overloads of the zip function for all 22 Tuple sizes. A code generator would probably help you with this.

Ken Bloom
+6  A: 

I don't believe it's possible to generate a list of tuples of arbitrary size, but the transpose function does exactly what you need if you don't mind getting a list of lists instead.

pumpkin
Thanks, that works perfectly! As I go into my specific use case, I see that a list of lists would be better anyway, as I need to map and reduce the various sub-lists.
pr1001
+2  A: 

I don't believe that's possible without being repetitive. For one simple reason: you can't define the returning type of the function you are asking for.

For instance, if your input was List(List(1,2), List(3,4)), then the return type would be List[Tuple2[Int]]. If it had three elements, the return type would be List[Tuple3[Int]], and so on.

You could return List[AnyRef], or even List[Product], and then make a bunch of cases, one for each condition.

As for general List transposition, this works:

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