6
scala> val a = List(1,2)
a: List[Int] = List(1, 2)

scala> val b = List(3,4)
b: List[Int] = List(3, 4)

scala> val c = List(5,6)
c: List[Int] = List(5, 6)

scala> val d = List(7,8)
d: List[Int] = List(7, 8)

scala> (a,b,c).zipped.toList
res6: List[(Int, Int, Int)] = List((1,3,5), (2,4,6))

Now:

scala> (a,b,c,d).zipped.toList
<console>:12: error: value zipped is not a member of (List[Int], List[Int], List[Int],     List[Int])
              (a,b,c,d).zipped.toList
                       ^

I've searched for this elsewhere, including this one and this one, but no conclusive answer.

I want to do the following or similar:

for((itemA,itemB,itemC,itemD) <- (something)) yield itemA + itemB + itemC + itemD

Any suggestions?

Community
  • 1
  • 1
fracca
  • 2,417
  • 1
  • 23
  • 22
  • 1
    Related? http://stackoverflow.com/questions/1664439/can-i-zip-more-than-two-lists-together-in-scala – WeaklyTyped Jun 12 '13 at 15:37
  • the last answer, the combinedLists almost produces the expected result, however, it does it in reverse order. I'm trying to work out how to make it produce the correct output (instead of reversing the order of the parameters. it also produces a list of values, not a tuple. thanks! – fracca Jun 12 '13 at 15:52
  • `List(a,b,c,d).transpose` gives this `List(List(1, 3, 5, 7), List(2, 4, 6, 8))`. Then you could use shapeless to get a list of tuples `List((1,3,5,7), (2,4,6,8))`. See this answer on shapeless: http://stackoverflow.com/a/11307342/390708 – Brian Jun 12 '13 at 16:22
  • i've tried to do the for comprehension with shapeless but still didn't work. thanks – fracca Jun 12 '13 at 17:01

4 Answers4

3

Short answer:

for (List(w,x,y,z) <- List(a,b,c,d).transpose) yield (w,x,y,z)
  // List[(Int, Int, Int, Int)] = List((1,3,5,7), (2,4,6,8))

Why you want them as tuples, I'm not sure, but a slightly more interesting case would be when your lists are of different types, and for example, you want to combine them into a list of objects:

case class Person(name: String, age: Int, height: Double, weight: Double)
val names =   List("Alf", "Betty")
val ages =    List(22, 33)
val heights = List(111.1, 122.2)
val weights = List(70.1, 80.2)
val persons: List[Person] = ???

Solution 1: using transpose, as above:

for { List(name: String, age: Int, height: Double, weight: Double) <- 
        List(names, ages, heights, weights).transpose
    } yield Person(name, age, height, weight)

Here, we need the type annotations in the List extractor, because transpose gives a List[List[Any]].

Solution 2: using iterators:

val namesIt   = names.iterator
val agesIt    = ages.iterator
val heightsIt = heights.iterator
val weightsIt = weights.iterator

for { name <- names } 
  yield Person(namesIt.next, agesIt.next, heightsIt.next, weightsIt.next)

Some people would avoid iterators because they involve mutable state and so are not "functional". But they're easy to understand if you come from the Java world and might be suitable if what you actually have are already iterators (input streams etc).

Luigi Plinge
  • 50,650
  • 20
  • 113
  • 180
  • 1
    I like the solution 1. I indeed have multiple types, and need to generate a case class in my yield. This allows me to select the values in a nice type safe declarative way. cheers – fracca Jun 13 '13 at 09:28
1

Shameless plug-- product-collections does something similar:

 a flatZip b flatZip c flatZip d
 res0: org.catch22.collections.immutable.CollSeq4[Int,Int,Int,Int] = 
 CollSeq((1,3,5,7),
         (2,4,6,8))

 scala> res0(0) //first row
 res1: Product4[Int,Int,Int,Int] = (1,3,5,7)

 scala> res0._1 //first column
 res2: Seq[Int] = List(1, 2)
Mark Lister
  • 1,103
  • 6
  • 16
0

found a possible solution, although it's very imperative to my taste:

  val a = List(1,2)
  val b = List(3,4)
  val c = List(5,6)
  val d = List(7,8)

  val g : List[Tuple4[Int,Int,Int,Int]] = {
    a.zipWithIndex.map { case (value,index) => (value, b(index), c(index), d(index))}  
  }

zipWithIndex would allow me to go through all the other collections. However, i'm sure there's a better way to do this. Any suggestions?

Previous attempts included:

Ryan LeCompte's zipMany or transpose.

however, it a List, not a tuple4. this is not as convenient to work with since i can't name the variables.

Tranpose it's already built in in the standard library and doesn't require higher kinds imports so it's preferrable, but not ideal.

I also, incorrectly, tried the following example with Shapeless

scala> import Traversables._
import Tuples._
import Traversables._
import Tuples._
import scala.language.postfixOps

scala> val a = List(1,2)
a: List[Int] = List(1, 2)

scala> val b = List(3,4)
b: List[Int] = List(3, 4)

scala> val c = List(5,6)
c: List[Int] = List(5, 6)

scala> val d = List(7,8)
d: List[Int] = List(7, 8)

scala> val x = List(a,b,c,d).toHList[Int :: Int :: Int :: Int :: HNil] map tupled
x: Option[(Int, Int, Int, Int)] = None
fracca
  • 2,417
  • 1
  • 23
  • 22
0
       val g = List(a,b,c,d)
   val result = ( g.map(x=>x(0)), g.map(x=>x(1) ) )

result : (List(1, 3, 5, 7),List(2, 4, 6, 8))

basic, zipped assit tuple2 , tuple3 http://www.scala-lang.org/api/current/index.html#scala.runtime.Tuple3Zipped so, You want 'tuple4zippped' you make it

gool luck

bistros
  • 1,139
  • 1
  • 9
  • 23