2011-08-20 16 views
7

Esiste un modo per manipolare più valori di una tupla senza utilizzare una variabile temporanea e iniziare una nuova istruzione?Manipolazione delle tuple

Dire che ho un metodo che restituisce una tupla e voglio fare qualcosa con quei valori in linea.

ad es. se voglio dividere una stringa ad un certo punto e invertire i pezzi

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

posso fare

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

(richiede variabili temporanee e nuova dichiarazione) o

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

(opere , ma sembra un po 'sporco, creando un singolo elemento Elenco solo per questo) o

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

(funziona per questo particolare esempio, ma solo perché esiste un metodo swap che fa ciò che voglio, quindi non è molto generale).

Il metodo zipped su tuple sembra essere solo per le tuple delle liste.

Come un altro esempio, come è possibile trasformare la tupla ('a, 'b, 'c) in ('b, 'a, 'c) in un'unica istruzione?

risposta

9

Le tuple sono solo un tipo di ritorno conveniente, e non si presume che si possano compiere complicate manipolazioni con esso. Inoltre ci sono stati simili discussion su scala forum.

Circa l'ultimo esempio, non è stato possibile trovare qualcosa di meglio della corrispondenza del modello.

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

L'abbinamento di modelli è buono! 's.splitAt (n) match {case (a, b) => b + a}' funziona per la prima parte –

+2

È un peccato che non ci sia un metodo 'fold' nella libreria standard; allora potresti semplicemente 's.splitAt (n) .fold ((a, b) => b + a)', e sarebbe anche più efficiente. (Sì, certo che l'ho creato da solo.) –

+0

Fold è un buon nome per questo. Ho aggiornato la mia risposta. –

7

Sfortunatamente, i metodi incorporati sulle tuple sono pretty limited.

Forse si vuole qualcosa come questi nella tua libreria personale,

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 le opportune conversioni implicite, si potrebbe fare,

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) 

Un'alternativa a l'ultima espressione sarebbe la "pipe "operatore |> (scaricalo da Scalaz o here),

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

Questo sarebbe bello, se non fosse per le annotazioni richieste,

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

ne dici di questo?

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

[Modifica: Ho appena notato che i tuoi argomenti per funzionare sono invertiti. In questo caso, si dovrà rinunciare sintassi segnaposto e invece andare per: (. Come dimostrato da @ 4E6) s.splitAt(n) |> Function.tupled((a, b) => b + a)]

Per il vostro ultimo esempio, non si può pensare a qualcosa di meglio di un pattern match

0

Con la versione di sviluppo attuale del shapeless, è possibile raggiungere questo obiettivo senza disimballare la tupla:

import shapeless.syntax.std.tuple._ 

val s = "abcdefgh" 
val n = 3 

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

penso che non dovrebbe essere necessario attendere troppo a lungo (questione di giorni direi) prima che la sintassi dei metodi dell'ultima riga venga pulita, e puoi semplicemente scrivere

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