2011-10-08 2 views
7

Я новичок в Скале, я просто пишу простую функцию, чтобы отменить данную строку:Scala обратная строка

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

выход дает обратно scala.collection.immutable.IndexedSeq [Char] , и не может преобразовать его в строку. (или это что-то еще?)

Как написать эту функцию?

ответ

19

Обратите внимание, что есть уже определенная функция:

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

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

Но если вы хотите сделать это самостоятельно:

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

или (иногда лучше использовать until, но, вероятно, не в в этом случае)

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

Также обратите внимание, что если вы используете обратный подсчет (от большего значения 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

спасибо om-nom-nom, я хочу реализовать его сам, чтобы я мог учиться :) – Dzhu

7

Как указано ом-ном-ном, обратите внимание на by -1 (иначе вы не очень переборе и ваш результат будет пустым). Другой трюк, который вы можете использовать, - collection.breakOut.

Она также может быть предоставлена ​​for понимания, как это:

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

reverse("foo") 
// String = oof 

Преимущество использования breakOut является то, что он будет избегать создания промежуточной структуры, как и в mkString растворе.

примечание: breakOut задействует CanBuildFrom и строитель, которые являются частью фундамента переработана библиотека коллекции, введенным в Скале 2.8.0

+0

Nice one! Никогда не думал о 'breakOut' таким образом. –

8

Вы также могли бы написать это с помощью рекурсивного подхода (бросание этого в только для удовольствия)

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

Это не будет оптимизировано – gurghet

10

Вот краткая версия

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

редактировать : или еще короче, мы имеем фантастически загадочные

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

, но я бы не рекомендовал это ...

+2

Hi Luigi, можете ли вы дать короткое объяснение для своего кода?спасибо – Dzhu

+1

Жаль, что я не подумал об этом. @Dzhu это просто использование 'foldLeft' (' /: 'это просто короткое имя для этого метода), которое принимает начальное значение, а затем применяет оператор к каждому значению последовательности слева направо. В этом случае последовательность - это строка, и оператор просто добавляет символы строки к результату. –

+0

@Dzhu '" "/: s' - вызов метода в инфиксной нотации. Вызов находится '' 'с аргументом' '' ', потому что метод' /: 'заканчивается на': '. Если вы посмотрите на String в документах Scala, вы не найдете их, так как это всего лишь класс Java, но вы найдете 'StringOps', для которого строки неявно преобразуются, и здесь вы найдете метод' /: '. Он находится в карри и принимает второй аргумент, который является (здесь) анонимной функцией типа '(String, Char) => String'. См. Также http://stackoverflow.com/q/7339618/770361, http://stackoverflow.com/questions/2293592/functional-programming-scala-map-and-fold-left/2303291#2303291 –

3

Все вышеперечисленные ответы верны, и вот мое взятие :

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 
Смежные вопросы