Dzhu
Dzhu

Reputation: 4381

Scala reverse string

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 ?

Upvotes: 15

Views: 37379

Answers (8)

The fourth bird
The fourth bird

Reputation: 163447

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

Upvotes: 0

Sean
Sean

Reputation: 1

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

Upvotes: 0

Igor Dorokhov
Igor Dorokhov

Reputation: 11

  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
  }

Upvotes: 0

Sudheer Aedama
Sudheer Aedama

Reputation: 2144

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

Upvotes: 4

Luigi Plinge
Luigi Plinge

Reputation: 51109

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...

Upvotes: 12

Thomas Lockney
Thomas Lockney

Reputation: 2597

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
}

Upvotes: 9

om-nom-nom
om-nom-nom

Reputation: 62835

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)

Upvotes: 29

huynhjl
huynhjl

Reputation: 41646

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

Upvotes: 8

Related Questions