Check for Palindromes [spoilers][solved]

Check for Palindromes [spoilers][solved]
0

#1

Here is my code that i pieced together, however i would like some advice on where i could have had more efficient/prettier code.

function palindrome(str) {
  var word = str.replace(/[^0-9a-zA-Z]/gi,'').toLowerCase();
  var array = word.split('');
  var newWord = array.reverse().join('');

  if(word == newWord){
    return true;
  }
  else{
    return false;
  }

}

#2

Well, you can rewrite the regex as /[\W_]/g,'' because:

  \W   matches any non-word character (equal to [^a-zA-Z0-9_])
  _    matches the character _ literally

The i flag is redundant.

Also, you can reverse a string faster if you avoid an array and instead build a new string by concatenating (adding) the letters one by one in reverse order, using a loop.

Here’s a quick benchmark test comparing the two approaches:

Expand for benchmark script
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite;
var str = 'The quick brown fox jumped over the lazy dog';


function arrayVersion(str) {
  return str.split('').reverse().join('');
}

function concatVersion(str) {
  var newStr = "";
  for (var i = str.length -1; i > -1; i--) {
    newStr = newStr + str[i];
  }
  return newStr;
}


// add tests
suite.add('arrayVersion', function() {
  arrayVersion(str)
})
.add('concatVersion', function() {
  concatVersion(str)
})
// add listeners
.on('cycle', function(event) {
    console.log(String(event.target));
})
.on('complete', function() {
    console.log('Fastest is ' + this.filter('fastest').map('name'));
})
// run async
.run({ 'async': true });

The output from the test is this:

benchmark-testing ➤ node reverseString.js
arrayVersion x 243,044 ops/sec ±1.05% (87 runs sampled)
concatVersion x 1,665,243 ops/sec ±2.00% (87 runs sampled)
Fastest is concatVersion

So you can see it’s nearly 7 times faster to do it the (admittedly uglier) way.


Is the style of the advanced solutions the best?
#3

Thank you for this! I assumed shorter code meant more efficient but that does not seem to always be the case.


#4

Yeah, I know what you mean. I literally only learned this a few days ago!

As you do more benchmark testing you begin to see what sorts of thing ‘cost’ more. In your example, even though the code is shorter, you are asking the function to make an array, reverse the array, and then join it back up and turn it back into a string.

That sounds easy enough, but the hidden costs are probably in those string and array methods you are calling (split, reverse, and join).

Each of those are their own functions (methods). Imagine how you would spilt a string into an array of individual letters. You’d probably make the array, then do a for loop through the string pushing each letter to the array. Then to reverse that array, you’d probably make another array and use a for loop to push each of those to the new array in reverse order. Then to join it up you’d likely need another for loop to take each item in the new array and concatenate a string.

Once you think through how you’d implement the string and array methods yourself, it’s easier to spot potentially hidden loops and temporary object creation that add processing overhead.

Note: I haven’t actually read the code for the split, reverse, and join methods, so I may be way off in my guess as to how they are implemented!