2012-03-09 9 views
30

que estoy tratando de zip múltiples secuencias para formar una larga tupla:Zip múltiples secuencias

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 

Lo que me sale:

List[(((Int, Char), String), Boolean)] = 
    List((((1,a),Alpha),true), (((2,b),Beta),false), (((3,c),Gamma),false)) 

Sin embargo, me gustaría obtener una secuencia de planas tuplas :

List[(Int, Char, String, Boolean)] = 
    List((1,a,Alpha,true), (2,b,Beta,false), (3,c,Gamma,false)) 

ahora que puedo hacer:

List(ints, chars, strings, bools).transpose 

Pero vuelve débilmente tipada List[List[Any]]. También puedo hacer (ints, chars, strings).zipped, pero zipped funciona solo en 2-tuplas y 3-tuplas.

¿Existe alguna manera de comprimir (arbitrariamente) el número de secuencias de igual longitud fácilmente?

Respuesta

11

Aquí hay una manera de resolver su ejemplo, pero esto no es para un número arbitrario de secuencias.

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 

no creo que es posible hacerlo de forma genérica para tuplas de longitud arbitraria, al menos no con este tipo de solución. Las tuplas tienen caracteres fuertes, y el sistema de tipos no permite especificar una cantidad variable de parámetros de tipo, hasta donde yo sé, lo que hace imposible hacer una versión generalizada de f2 y f3 que tome una tupla de longitud arbitraria ((A,B),C,D,...) (que devolvería una tupla (A,B,C,D,...)).

Si hubiera una manera de especificar un número variable de parámetros de tipo, no necesitaríamos los rasgos Tuple1, Tuple2, ... Tuple22 en la biblioteca estándar de Scala.

+0

+1, gracias. Actualmente estoy usando el enfoque 'map', pero' t._1._1, t._1._2, t._2, t._3' no es muy legible, y en mi caso necesito una 5-tupla, que empeora las cosas Realmente no necesito admitir listas de longitud arbitraria, pero * lo suficientemente largo *. Pensé que tal vez haya algunos métodos especializados que devuelven tuplas con tipado fuerte de longitud correcta, pero entiendo tu punto sobre el problema 'Tuple1'-'Tuple22'. –

+6

Con la coincidencia de patrones, puede deshacerse de la sintaxis ilegible '._1, ._2' etc.:' def f2 [A, B, C] (t: ((A, B), C)) t coincidencia {case ((a, b), c) => (a, b, c)} ' – Jesper

2

Comparto la opinión de Jesper de que esto no es posible en general, ya que cada tupla se representa como una clase separada en el código fuente, por lo que debe escribir un código separado para acceder a ellas a menos que use un generador de código.

Pero quiero agregar otra posible solución. Si desea conservar la escritura de sus entradas de tupla, pero está interesado en un tipo más similar a una colección, quizás las listas HLists (listas heterogéneas) sean para usted. Puede google hlist scala para implementaciones y explicaciones.

5

Usando shapeless, se podría hacer:

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

(no estoy seguro, si hay más implicts definen lo que le permite evitar los map y realizar copias de y hacia adelante conversiones)

[Editar : Esta parte ya no es verdad.

Tenga en cuenta que los documentos informes dicen que solo las conversiones hasta Tuple4 son compatibles actualmente. Tendría que crear manualmente HLists entonces.]

+0

Realmente sin forma maneja todas las aries hasta 22. –

+0

Ah, vale. Iba por el comentario en converssions.scala sin realmente verificarlo. – Debilski

+0

Vaya ... desactualizado comentario. Corregido ahora. Gracias por el aviso. –

6

me gustaría crear una clase que representa los conjuntos de datos:

case class DataSet(int: Int, char: Char, string: String, bool: Boolean) 

Esto trae los nombres más agradables para acceder a los valores en lugar de _N que tenemos en tuplas. Si las listas pueden tener diferentes tamaños el menor debe ser elegido:

val min = List(ints, chars, strings, bools).map(_.size).min 

Ahora es posible extraer los datos:

val dataSets = (0 until min) map { i => DataSet(ints(i), chars(i), strings(i), bools(i)) } 

Cuando las listas originales pueden contener una gran cantidad de valores que es mejor hacerlos en un IndexedSeq para que el tiempo de acceso sea O (1).

1

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

Esto funciona actualmente para aridad 1 - 22. Como se puede ver los tipos se conservan.

3

creo que la coincidencia de patrones es una buena opción

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

o puede agregar el tipo, así

(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))** 
Cuestiones relacionadas