I am trying to zip
multiple sequences to form a long tuple:
val ints = List(1,2,3)
val chars = List(\'a\', \'b\', \'c\')
val strings = List(\"Al
Using product-collections
scala> ints flatZip chars flatZip strings flatZip bools
res0: org.catch22.collections.immutable.CollSeq4[Int,Char,String,Boolean] =
CollSeq((1,a,Alpha,true),
(2,b,Beta,false),
(3,c,Gamma,false))
This currently works for arity 1 - 22. As you can see the types are preserved.
Using shapeless, you could do:
import shapeless.Tuples._
val ints = (1, 2, 3)
val chars = ('a', 'b', 'c')
val megatuple = (ints, chars)
val megahlist = (megatuple hlisted) map hlisted
val transposed = (mhlist transpose) map tupled tupled
scala> transposed
res: ((Int, Char), (Int, Char), (Int, Char)) = ((1,a),(2,b),(3,c))
(not sure, if there are more implicts defined which lets you avoid the map
and back-and-forth conversions)
[Edit: This part is not true anymore.
Note that the shapeless docs say, only conversions up to Tuple4
are currently supported. You’d have to manually create the HLists then.]
Here is another solution which would work for your problem.
ints zip chars zip strings zip bools map{ case (((a, b), c), d) => (a,b,c,d)}
I share Jesper's opinion that this is not possible in general, since each tuple arity is represented as separate class in source code, so you have to write separate code to access them unless using a code generator.
But I want to add another possible solution. If you want to preserve the typing of your tuple entries, but are otherwise interested in a more collection-like type, maybe HLists (heterogenous lists) are for you. You can google hlist scala for implementations and explanations.
Here's one way to solve your example, but this is not for an arbitrary number of sequences.
val ints = List(1,2,3)
val chars = List('a', 'b', 'c')
val strings = List("Alpha", "Beta", "Gamma")
val bools = List(true, false, false)
val input = ints zip chars zip strings zip bools
// Flattens a tuple ((A,B),C) into (A,B,C)
def f2[A,B,C](t: ((A,B),C)) = (t._1._1, t._1._2, t._2)
// Flattens a tuple ((A,B),C,D) into (A,B,C,D)
def f3[A,B,C,D](t: ((A,B),C,D)) = (t._1._1, t._1._2, t._2, t._3)
input map f2 map f3
I don't think it is possible to do it generically for tuples of arbitrary length, at least not with this kind of solution. Tuples are strongly-typed, and the type system doesn't allow you to specify a variable number of type parameters, as far as I know, which makes it impossible to make a generalized version of f2
and f3
that takes a tuple of arbitrary length ((A,B),C,D,...)
(that would return a tuple (A,B,C,D,...)
).
If there were a way to specify a variable number of type parameters, we wouldn't need traits Tuple1
, Tuple2
, ... Tuple22
in Scala's standard library.
I think pattern matching is a good option
val ints = List(1,2,3)
val chars = List('a', 'b', 'c')
val strings = List("Alpha", "Beta", "Gamma")
val bools = List(true, false, false)
(ints zip chars zip strings zip bools) map { case (((i,c),s),b) => (i,c,s,b)}
**res1: List[(Int, Char, java.lang.String, Boolean)] = List((1,a,Alpha,true), (2,b,Beta,false), (3,c,Gamma,false))**
or you can add type as well
(ints zip chars zip strings zip bools) map {case (((i:Int,c:Char),s:String),b:Boolean) => (i,c,s,b)}
**res2: List[(Int, Char, java.lang.String, Boolean)] = List((1,a,Alpha,true), (2,b,Beta,false), (3,c,Gamma,false))**