Scala reverse string
Asked Answered
H

8

15

I'm a newbie to scala, I'm just writing a simple function to reverse a given string:

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

the yield gives back a scala.collection.immutable.IndexedSeq[Char], and can not convert it to a String. (or is it something else?)

how do i write this function ?

Hornbeam answered 8/10, 2011 at 23:20 Comment(0)
U
29

Note that there is already defined function:

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

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

But if you want to do that by yourself:

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

or (sometimes it is better to use until, but probably not in that case)

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

Also, note that if you use reversed counting (from bigger one to less one value) you should specify negative step or you will get an empty set:

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)
Unproductive answered 8/10, 2011 at 23:30 Comment(1)
thanks om-nom-nom, i want to implement it myself so i can learn :)Hornbeam
C
12

Here's a short version

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

edit : or even shorter, we have the fantastically cryptic

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

but I wouldn't really recommend this...

Commination answered 9/10, 2011 at 0:11 Comment(3)
Hi Luigi, can you give a short explanation for your code? thanksHornbeam
Wish I had thought of this one. @Hornbeam it's just using a foldLeft (/: is just a short-hand name for that method) which takes an initial value and then applies an operator to each value of a sequence from left to right. In this case, the sequence is the string and the operator is just prepending the characters of the string to the result.Lontson
@Hornbeam "" /: s is a method call in infix notation. The call is on s with argument "" since the method /: ends in :. If you look up String in the Scala docs you won't find it since it's just the Java class, but you will find StringOps to which Strings are implicitly converted, and here you'll find the /: method. It is curried and takes a second argument, which is (here) an anonymous function of type (String, Char) => String. See also https://mcmap.net/q/699502/-scala-vector-fold-syntax-and-and/770361, #2294092Commination
L
9

You could also write this using a recursive approach (throwing this one in just for fun)

def reverse(s: String): String = {
  if (s.isEmpty) ""
  else reverse(s.tail) + s.head
}
Lontson answered 8/10, 2011 at 23:49 Comment(1)
This won't be optimizedSparoid
Z
8

As indicated by om-nom-nom, pay attention to the by -1 (otherwise you are not really iterating and your result will be empty). The other trick you can use is collection.breakOut.

It can also be provided to the for comprehension like this:

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

reverse("foo")
// String = oof

The benefit of using breakOut is that it will avoid creating a intermediate structure as in the mkString solution.

note: breakOut is leveraging CanBuildFrom and builders which are part of the foundation of the redesigned collection library introduced in scala 2.8.0

Zuzana answered 8/10, 2011 at 23:42 Comment(0)
S
4

All the above answers are correct and here's my take:

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
Shatterproof answered 9/1, 2014 at 2:20 Comment(0)
P
0
  def rev(s: String): String = {
    val str = s.toList
    def f(s: List[Char], acc: List[Char]): List[Char] = s match {
      case Nil => acc
      case x :: xs => f(xs, x :: acc)
    }
    f(str, Nil).mkString
  }
Prodrome answered 15/10, 2019 at 21:24 Comment(1)
Welcome to stackoverflow. In addition to the answer you've provided, please consider providing a brief explanation of why and how this fixes the issue.Langille
R
0

Here is my version of reversing a string.

scala> val sentence = "apple"
sentence: String = apple

scala> sentence.map(x => x.toString).reduce((x, y) => (y + x))
res9: String = elppa
Refugiorefulgence answered 16/12, 2022 at 6:38 Comment(0)
K
0

Another variation using tail recursion, using an inner function taking the first char of the remaining and prepending it to the accumulator.

import scala.annotation.tailrec

def reverse(s: String): String = {
  @tailrec
  def revTailRec(remaining: String, acc: String): String = {
    if (remaining.headOption.nonEmpty) revTailRec(remaining.tail, remaining.head + acc)
    else acc
  }
  revTailRec(s, "")
}

reverse("foobar")  // raboof
Kerekes answered 17/12, 2023 at 14:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.