DEV Community

loading...
Cover image for Reverse a String - Four JavaScript Solutions

Reverse a String - Four JavaScript Solutions

sarah_chima profile image Sarah Chima ・4 min read

This article was originally published on my blog

The reverse a string problem is a common algorithm problem. In this article, we will consider four JavaScript solutions to it.

A Little Background Info

Lately, I have been taking a course on data structures and algorithms. This is because I realized that I suck at it. This has not always been the case. When I started learning JavaScript, solving algorithm challenges was the fun part for me. I could stay up for hours late at night just trying to solve a challenge. But two years and many frontend projects later, it seems I've forgotten everything I learned. That is why I decided to go back to learn and practice.

Solid knowledge of data structures and algorithms comes with much practice. And what better way to remember what I learn that to write about it. That's why I am presenting to you the first part of a series of articles to come.

Let's delve into our algorithm challenge for today: Reversing a String

The Problem

Reversing a string is, well, reversing a string. Okay, here's the problem statement: Write a function that reverses a string. If you pass "Sarah" to the function, it should return "haraS" and "listen" should become "netsil". Got it?

Now, let's look at four javascript solutions.

Solution 1. Using the array reverse() method

Thanks to the Array.reverse() method, we can reverse an array without much stress. The reverse() method reverses an array in place. The first array element becomes the last, and the last array element becomes the first.

In our case though, we are working with strings. So this means that we have to convert the string to an array using the split method, reverse it using the reverse method and convert it back to a string using the join method. Here's the code example.

function reverseString(string) {
       //convert the string to an array
       let array = string.split("");

    //Use the reverse method
    array.reverse()

    //Convert it back to a string and return
    return array.join("")
}

Enter fullscreen mode Exit fullscreen mode

We can convert this to a one-liner using arrow function and implicit return.

const reverseString = (string) => string.split("").reverse().join('');
Enter fullscreen mode Exit fullscreen mode

That's it. One line of goodness. Let's move to the next solution.

Solution 2: Good Ol' For-loop

This is the classic example of reversing through a string. It might be one of the first methods that will come to your mind if you encounter this problem.

What we will do here is to create an empty string that will hold the reversed string, loop through each character in the string and append it to the beginning of the new string.

    function reverse(str) {
    let reverseString = "";

    for (let character of str) {
        reverseString = character + reverseString;
    }

    return reverseString
}
Enter fullscreen mode Exit fullscreen mode

Solution 3 - Using the Array.reduce() method

The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in single output value. You can read about it if you are not familiar with it.

To use the reduce method, we need to convert our string to an array. Next, we use the reduce method to convert it to a reversed string. The reducer, in this case, appends each character of the string to the beginning of the accumulator which, in the code below, is reversed.

function reverseString(string) {
    //convert the string to an array
    const array = string.split('');

    //use the reduce method to convert the array to a reversed string
    const reversedString = array.reduce((reversed, character) => {
        return character + reversed
    }, '')

    return reversedString
}
Enter fullscreen mode Exit fullscreen mode

This function above can further be reduced to :

const reverseString = (string) => {
    return string.split('').reduce((reversed, character) => character + reversed, '')
}
Enter fullscreen mode Exit fullscreen mode

Making it a one-liner and shortening the name of the variables used in the reduce method.

const reverseString = (string) => string.split('').reduce((rev, char) => char + rev, '')
Enter fullscreen mode Exit fullscreen mode

Solution 4 - Using recursion

Are you a friend of recursion? If not, let me introduce you to it.

Recursion is a way of solving a problem by using a function that calls itself. Each time the function calls itself, it reduces the problem into subproblems. This recursive call continues until a point is reached where the subproblem can be called without further recursion.

An important part of a recursive function is a base case. This is the condition(s) where the recursive call terminates to ensure it does not result in an infinite loop. You can find more explanations here.

Let's get back to 'reversing a string'. In this case, our base case is when the string is empty. We use the string.substring() method to get remove the first character in the string and pass the other characters to the function. Then we append the first character to our return statement as seen in the code below.

function reverse(string){
    //base case: if str is empty return str 
   if(string === ""){
        return string 
   } else{
        return reverse(string.substring(1)) + string[0]
   }
}
Enter fullscreen mode Exit fullscreen mode

We can use a ternary operator instead of if-else statements.

function reverse(string){
    return string ? reverse(string.substring(1)) + string[0] : string
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

So there you have it, four cools ways to reverse a string in JavaScript. Have any other solution to this problem, please share it in the comments. I would really love to know.

Got any question or feedback? please leave a comment.

Follow me on Instagram @sarah_codes_ where I regularly post software development tips and advice.

Discussion (26)

pic
Editor guide
Collapse
bugmagnet profile image
Bruce Axtens • Edited

Actually, you could take the recursion along a bit further and make it a prototype of String, viz:

String.prototype.flip = function () {
  return (this.length === 1) 
    ? this 
    : this.substr(1).flip() + this.substr(0, 1);
};

var original = "lewd i did live - evil did i dwel";
var reversed = original.flip();

Someone'll beat me to a blog post, likely.

Collapse
abraham profile image
Abraham Williams

It's generally recommended that you should not extend native prototypes.

developers.google.com/web/updates/...

Collapse
markwaterous profile image
Mark

shakes fist at MooTools

Collapse
aminmansuri profile image
hidden_dude • Edited

Wouldn't solution #2 (and maybe some of the others) cause an O(n2 ) problem?

for (let character of str) {
    reverseString = character + reverseString;
}

If str has N elements, and you do character + reverseString each time you get n*(n+1)/2 characters copied (ie. O(n2 )).

Whereas option#1 presumably uses only O(n) functions so it should be much faster as data grows and less stress on the GC.

I think it would be best to compare these with benchmarks (with large examples). Because I've found that the one place where code can get super slow is with successive concatenation in a for loop (as in option#2).

Collapse
sarah_chima profile image
Sarah Chima Author

Thanks for the suggestion and the analysis. In subsequent posts, I try to compare the solutions based on their performance.

Collapse
theodesp profile image
Theofanis Despoudis

What about an old classic way:

function reverse(str) {
  let result = str.split('');
  for (let i = 0, j = str.length - 1;i < j; i+=1, j-=1) {
    result[i] = str[j];
    result[j] = str[i];
  }

  return result.join('');
}
Enter fullscreen mode Exit fullscreen mode
Collapse
sarah_chima profile image
Sarah Chima Author

This is a good improvement to the solution 2. It reduces the loop time by half. Thanks for sharing.

Collapse
quantumsheep profile image
Nathanael Demacon

.split('') can be shortened:

[...string].reverse().join('')
Collapse
rhysbrettbowen profile image
Rhys Brett-Bowen

Also good because split will fail badly for some utf8 things like emojis

Collapse
bugmagnet profile image
Bruce Axtens

So after doing .call(), let's do .apply(), viz

Array.prototype.flip = function () {
    for (var i = 0; i < this.length / 2; i++) {
        var tmp = this[this.length - i - 1];
        this[this.length - i - 1] = this[i];
        this[i] = tmp;
    }
    return this;
}

var original = "lewd i did live - evil did i dwel";

var reversed = [].flip.apply(original.split("")).join("");

Okay, maybe it's time to do some real work now.

Collapse
bugmagnet profile image
Bruce Axtens

Going nuts here. More ideas, and for something as mundane as a reverse function. Monomania?

function flip3(string) {
  var result = Array(string.length);
  for (var i = string.length - 1, j = 0; i >= 0; i--, j++) {
    result[j] = string.charAt(i);
  }
  return result.join("");
}

function flip4(string) {
    var result = Array(string.length).fill(1);
    result.map(function (item,index) {
        var rhs = string.length - 1 - index;
        result[index] = string.charAt(index);
    });
    return result.join("");
}

Your mileage may vary on flip4's .fill() call. I'm having to use polyfills (long story) and if I don't fill the Array, .map() assumes that there's nothing there to work on.

I do have a couple of ideas yet to exorcise.

Collapse
quickhand profile image
quickhand

Short, sweet:

[...str].map((_,i,arr) => arr[arr.length-1-i])
Collapse
bugmagnet profile image
Bruce Axtens

I'd forgotten about that third parameter into map. Short, sweet, superb!

Collapse
bugmagnet profile image
Bruce Axtens • Edited

I'm not sure what you'd call this solution, but it does reverse the string:

var times = function (n, fn /*, args*/) {
  var args = [].slice.call(arguments).slice(1);
  for (var i = 0; i < n; i++) {
    fn.call(this, i, args);
  }
  return args[2];
}

var original = "lewd i did live - evil did i dwel";
var result = "";

var reversed = times(original.length, function (i, args) {
    args[2] = args[1].substr(i, 1) + args[2];
  }, original, result);

That's the first time I've written code that uses .call(). Won't be the last time!

Collapse
bugmagnet profile image
Bruce Axtens • Edited

This recursion thing is pretty cool. Here's another approach both as a String.prototype and as a standalone function:

String.prototype.flip2 = function() {
  if (1 >= this.length) return this;
  return (
    this.substr(-1) +
    this.substr(1, this.length - 2).flip2() +
    this.substr(0, 1)
  );
};

function flip2(string) {
  if (1 >= string.length) return string;
  return (
    string.substr(-1) +
    flip2(string.substr(1, string.length - 2)) +
    string.substr(0, 1)
  );
}

var x = "lewd i did live - evil did i dwel".flip2();
var y = flip2("lewd i did live - evil did i dwel");

The approach is to take the first character and put it last, take the last character and put it first, and do that to the stuff in the middle.

It's been through the Closure Compiler, thus the 1 >= this.length.

Collapse
mgranados profile image
Martín Granados García

Nice idea for blog posts! It is helpful for people wanting to learn and helpful for you to practice the algos! 💯

Collapse
sarah_chima profile image
Sarah Chima Author

Thank you, Martin.

Collapse
fullzero5 profile image
Collapse
dmikester1 profile image
Mike Dodge

What is this crazy black magic I'm looking at?

Collapse
javver profile image
Javier Cardona • Edited

Just don't use any emoji with skin color modifier though...

"🤷🏻‍♂️" split on '' becomes 7 "strings"

"🤷🏻‍♂️".split('').reverse().map(c => c.charCodeAt(0).toString(16))
// ["fe0f", "2642", "200d", "dffb", "d83c", "dd37", "d83e"]

That reversed looks... weird.
"️♂‍�🄷�"

Collapse
leobm profile image
Felix Wittmann • Edited

certainly not very fast, but I'd like destructuring assignment and recursion :)

let reverse = ([h,...r]) => r.length>0 && reverse(r)+h || h;
Collapse
sir_wernich profile image
Wernich ️

first thing i thought of was reduceRight (works in the opposite direction to reduce), with no split or join :)

Array.from(str).reduceRight((acc, ch) => acc.concat(ch));
Collapse
nsriram profile image
Sriram Narasimhan

Another solution using for loop, but only iterates half the time.

function reverse(str){
  let reversedStr = str
  const length = reversedStr.length
  for(i=0; i< length/2; i++){
    const endIndex = length - (i+1)
    if(endIndex > i){
      const pre = reversedStr.substring(0, i)
      const beginChar = reversedStr.substring(i, i+1)
      const unsorted = reversedStr.substring(i+1,endIndex)
      const endChar = reversedStr.charAt(endIndex)
      const post = reversedStr.substring(endIndex+1)

      //An overkill of swap !
      reversedStr = pre+endChar+unsorted+beginChar+post         
    }
  }
  return reversedStr
}

console.log(reverse("1234567"))
console.log(reverse("123456"))
console.log(reverse("abracadabra"))
console.log(reverse("esrever"))
Collapse
gregbacchus profile image
Greg Bacchus

Would be great to see a performance comparison between then all.

Collapse
sarah_chima profile image
Sarah Chima Author

Yes, I'll consider adding that in subsequent posts. Thanks for the suggestion.

Collapse
vyasriday profile image
Hridayesh Sharma

You can find code snippets here. I did the same a couple of days ago
github.com/vyasriday/js-snippets/b...