2012-09-12 11 views
12

Supongamos que tengo la siguiente lista de tuplas:Scala: Cómo convertir los elementos de tupla a listas

val tuples = listOfStrings.map(string => { 
      val split = string.split(":") 
      (split(0), split(1), split(2)) 
     }) 

me gustaría obtener la fracción (0) en una lista, dividida (1) en otra lista y pronto. Una forma sencilla de esto podría lograrse es mediante la escritura:

list1 = tuples.map(x => x._1).toList 
list2 = tuples.map(x => x._2).toList 
list3 = tuples.map(x => x._3).toList 

¿Hay una manera más elegante (funcional) de lograr lo anterior sin necesidad de escribir 3 declaraciones por separado?

Respuesta

11

Esto le dará a su resultado como una lista de lista:

tuples.map{t => List(t._1, t._2, t._3)}.transpose 

Si desea almacenarlos en variables locales, acaba de hacer:

val List(l1,l2,l3) = tuples.map{t => List(t._1, t._2, t._3)}.transpose 

ACTUALIZACIÓN: Según lo señalado por Blaisorblade, la biblioteca estándar en realidad tiene un método integrado para esto: unzip3, que es como unzip pero para triples en vez de pares:

val (l1, l2, l3) = tuples.unzip3 

Ni que decir tiene, que debe favorecer este método sobre mi solución enrollados a mano por encima (pero para tuplas de arity> 3, esto todavía se aplicaría).

+0

demasiado lento :) estaba a punto de publicar: 'tuples.map {t => t._1 :: :: t._2 t._3 :: Nil} .transpose' nice one. +1 –

+0

Mala idea, debería usar descomprimir de la otra respuesta: http://stackoverflow.com/a/17281359/53974 – Blaisorblade

+0

@Balisorblade: Tengo que estar en desacuerdo. Esto sería cierto si fuera un 'Tuple2', pero es un' Tuple3'. 'unzip' solo maneja pares de descompresión, y el propio ejemplo de jeshan muestra una lista de' Tuple3', no 'Tuple2'. –

1

Puede escribir las declaraciones en una sola línea.

Como

(list1, list2, list3) = tuples.foldRight((List[String](), List[String](), List[String]()))((a,b) => (a._1 :: b._1, a._2 :: b._2, a._3 :: b._3)) 
+1

pero es bastante críptico para su posible lector –

0

No sé lo elegante pero podría hacerlo en una línea sin el paso intermedio de almacenar las tuplas. Tal vez sea un poco difícil de leer ... ejemplo

(for(split <- listOfStrings.map(_.split(":"))) 
    yield List(split(0), split(1), split(2))).transpose 

repl:

scala> listOfStrings 
res1: List[java.lang.String] = List(a:b:c, d:e:f, g:h:i) 

scala> (for(split <- listOfStrings.map(_.split(":"))) 
    | yield List(split(0), split(1), split(2))).transpose 
res2: List[List[java.lang.String]] = List(List(a, d, g), List(b, e, h), List(c, f, i)) 
3

Si quieres algo que se puede utilizar para tamaños de tupla arbitrarias:

val tupleSize = 3 
0.until(tupleSize).toList 
    .map(x => (_:Product).productElement(x).asInstanceOf[String]) 
    .map(tuples.map(_)) 

Obviamente, esto podría expresarse de manera más elegante si tuviera una Lista de matrices en su lugar.

+3

+1 para una solución sin _1, _2 y _3! –

+1

O simplemente: 'tuples.map (_. ProductIterator.toList) .transpose.asInstanceOf [List [List [String]]'. Iba a publicar esta solución, pero el reparto es una pena. –

+0

Pensé en esa solución también, pero esta versión es probablemente más eficiente que la transposición. El lanzamiento se puede evitar si tomamos una 'Lista' de' Array's como entrada. –

10

Usted desea descomprimir:

scala> val (numbers, homonyms) = List(("one", "won"), ("two", "too")).unzip 
numbers: List[java.lang.String] = List(one, two) 
homonyms: List[java.lang.String] = List(won, too) 
+2

Esto solo funciona en pares, no en ningún otro tipo de tupla –

+1

Hay unzip3 para triples. – Blaisorblade

Cuestiones relacionadas