Zip multiple sequences

后端 未结 7 1715
眼角桃花
眼角桃花 2020-12-06 09:20

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         


        
相关标签:
7条回答
  • 2020-12-06 09:27

    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.

    0 讨论(0)
  • 2020-12-06 09:35

    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.]

    0 讨论(0)
  • 2020-12-06 09:40

    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)}
    
    0 讨论(0)
  • 2020-12-06 09:42

    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.

    0 讨论(0)
  • 2020-12-06 09:47

    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.

    0 讨论(0)
  • 2020-12-06 09:47

    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))**
    
    0 讨论(0)
提交回复
热议问题