2011-08-20 15 views
7

¿Hay alguna manera de manipular múltiples valores de una tupla sin usar una variable temporal y comenzar una nueva instrucción?Manipulando tuplas

Digamos que tengo un método que devuelve una tupla y quiero hacer algo con esos valores en línea.

p. Ej. si quiero dividir una cadena en un punto determinado y revertir las piezas

def backToFront(s: String, n:Int) = s.splitAt(n)... 

que puedo hacer

val (a, b) = s.splitAt(n) 
b + a 

(requiere variables temporales y nueva declaración) o

List(s.splitAt(n)).map(i => i._2 + i._1).head 

(obras , pero parece un poco sucio, creando un solo elemento Lista solo para esto) o

s.splitAt(n).swap.productIterator.mkString 

(funciona para este ejemplo en particular, pero solo porque existe un método swap que hace lo que quiero, por lo que no es muy general).

El método zipped en tuplas parece ser solo para tuplas de listas.

Como otro ejemplo, ¿cómo podría convertir la tupla ('a, 'b, 'c) en ('b, 'a, 'c) en una sola declaración?

Respuesta

9

Las tuplas son simplemente un tipo de devolución conveniente, y no se supone que realice manipulaciones complicadas con ella. También hubo similares discussion en los foros de scala.

Sobre el último ejemplo, no se pudo encontrar nada mejor que la coincidencia de patrones.

('a, 'b, 'c) match { case (a, b, c) => (b, a ,c) } 
+0

¡La coincidencia de patrones es buena! 's.splitAt (n) match {case (a, b) => b + a}' funciona para la primera parte –

+2

Es una pena que no haya un método 'fold' en la biblioteca estándar; entonces podría simplemente 's.splitAt (n) .fold ((a, b) => b + a)', y sería más eficiente también. (Sí, por supuesto que he hecho el mío.) –

+0

Fold es un buen nombre para ello. Actualicé mi respuesta. –

7

Lamentablemente, los métodos integrados en las tuplas son pretty limited.

Tal vez usted quiere algo así como estos en su biblioteca personal,

def fold2[A, B, C](x: (A, B))(f: (A, B) => C): C = f(x._1, x._2) 
def fold3[A, B, C, D](x: (A, B, C))(f: (A, B, C) => D): D = f(x._1, x._2, x._3) 

Con las conversiones implícitas apropiadas, se podría hacer,

scala> "hello world".splitAt(5).swap.fold(_ + _) 
res1: java.lang.String = " worldhello" 

scala> (1, 2, 3).fold((a, b, c) => (b, c, a)) 
res2: (Int, Int, Int) = (2,3,1) 

Una alternativa a la última expresión sería la "pipa "operador |> (consígalo de Scalaz o here),

scala> ('a, 'b, 'c) |> (t => (t._2, t._3, t._1)) 
res3: (Symbol, Symbol, Symbol) = ('b,'c,'a) 

Esto estaría bien, si no fuera por las anotaciones necesarias,

scala> ("hello ", "world") |> (((_: String) + (_: String)).tupled) 
res4: java.lang.String = hello world 
2

¿Qué tal esto?

s.splitAt(n) |> Function.tupled(_ + _) 

[Editar: Acaba de notar que sus argumentos para la función se invierten. En ese caso, tendrá que renunciar a la sintaxis marcador de posición y en lugar de ir a: (. Como se muestra por @ 4E6) s.splitAt(n) |> Function.tupled((a, b) => b + a)]

Para su último ejemplo, no se puede pensar en nada mejor que una coincidencia de patrón

0

Con la versión de desarrollo actual de shapeless, se puede lograr esto sin desembalar la tupla:

import shapeless.syntax.std.tuple._ 

val s = "abcdefgh" 
val n = 3 

s.splitAt(n).rotateRight[shapeless.Nat._1].mkString("", "", "") // "defghabc" 

creo que no debería tener que esperar demasiado tiempo (cuestión de días que diría) antes de limpiar la sintaxis de los métodos de la última línea, y simplemente escriba

s.splitAt(n).rotateRight(1).mkString