2011-10-08 16 views
7

Soy un novato a Scala, sólo estoy escribiendo una simple función de revertir una cadena dada:Scala cadena inversa

def reverse(s: String) : String 
    for(i <- s.length - 1 to 0) yield s(i) 

el rendimiento devuelve una scala.collection.immutable.IndexedSeq [Char] y no puede convertirlo en una cadena. (¿o es algo más?)

¿Cómo escribo esta función? función

Respuesta

19

nota que ya está definido:

scala> val x = "scala is awesome" 
x: java.lang.String = scala is awesome 

scala> x.reverse 
res1: String = emosewa si alacs 

Pero si quieres hacer eso por sí mismo:

def reverse(s: String) : String = 
(for(i <- s.length - 1 to 0 by -1) yield s(i)).mkString 

o (a veces es mejor usar until, pero probablemente no en ese caso)

def reverse(s: String) : String = 
(for(i <- s.length until 0 by -1) yield s(i-1)).mkString 

Además, tenga en cuenta que si se utiliza el recuento invertido (de mayor o ne al menos un valor) se debe especificar el paso negativo o se obtendrá un conjunto vacío:

scala> for(i <- x.length until 0) yield i 
res2: scala.collection.immutable.IndexedSeq[Int] = Vector() 

scala> for(i <- x.length until 0 by -1) yield i 
res3: scala.collection.immutable.IndexedSeq[Int] = Vector(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 
+0

gracias om-nom-nom, quiero implementarlo por mí mismo para que pueda aprender :) – Dzhu

7

Según lo indicado por om-nom-nom, prestar atención a la by -1 (de lo contrario usted no está realmente iterando y el resultado de su estará vacío). El otro truco que puedes usar es collection.breakOut.

También se puede proporcionar a la for comprensión de esta manera:

def reverse(s: String): String = 
    (for(i <- s.length - 1 to 0 by -1) yield s(i))(collection.breakOut) 

reverse("foo") 
// String = oof 

La ventaja de utilizar breakOut es que va a evitar la creación de una estructura intermedia como en la solución mkString.

nota: breakOut está aprovechando CanBuildFrom y constructores que forman parte de la fundación de la biblioteca de recogida rediseñado introducido en Scala 2.8.0

+0

¡Bonito! Nunca pensé en 'breakOut' de esa manera. –

8

También podría escribir esto utilizando un enfoque recursivo (devolver éste en tan sólo por diversión)

def reverse(s: String): String = { 
    if (s.isEmpty) "" 
    else reverse(s.tail) + s.head 
} 
+1

Esto no se optimizará – gurghet

10

Aquí hay una versión corta

def reverse(s: String) = ("" /: s)((a, x) => x + a) 

edición : o incluso más corto, tenemos el fantástico críptica

def reverse(s: String) = ("" /: s)(_.+:(_)) 

pero yo no recomendaría este ...

+2

Hola Luigi, ¿puedes dar una breve explicación de tu código?gracias – Dzhu

+1

Ojalá hubiera pensado en este. @Dzhu solo usa un 'foldLeft' (' /: 'es solo un nombre abreviado para ese método) que toma un valor inicial y luego aplica un operador a cada valor de una secuencia de izquierda a derecha. En este caso, la secuencia es la cadena y el operador está anteponiendo los caracteres de la cadena al resultado. –

+0

@Dzhu '" "/: s' es una llamada a método en notación infija. La llamada está en 's' con el argumento' "" 'ya que el método' /: 'termina en': '. Si busca String en los documentos de Scala, no lo encontrará, ya que es solo la clase Java, pero encontrará 'StringOps' en el que las cadenas se convierten implícitamente, y aquí encontrará el método' /: '. Se curry y toma un segundo argumento, que es (aquí) una función anónima de tipo '(String, Char) => String'. Ver también http://stackoverflow.com/q/7339618/770361, http://stackoverflow.com/questions/2293592/functional-programming-scala-map-and-fold-left/2303291#2303291 –

3

Todas las respuestas anteriores son correctas y aquí es mi opinión :

scala> val reverseString = (str: String) => str.foldLeft("")((accumulator, nextChar) => nextChar + accumulator) 
reverseString: String => java.lang.String = <function1> 

scala> reverseString.apply("qwerty") 
res0: java.lang.String = ytrewq