0

Recently I came across some code that is supposed to match these arrays try as I might I could not get all the pieces of the puzzle together to make sense

validateSequence([1,2,3,4,5,6,7,8,9]) === true
validateSequence([1,2,3,4,5,8,7,8,9]) === false
validateSequence([2,4,6,8,10]) === true
validateSequence([0,2,4,6,8]) === true
validateSequence([1,3,5,7,9]) === true
validateSequence([1,2,4,8,16,32,64]) === false
validateSequence([0,1,1,2,3,5,8,13,21,34]) === false

Here is the code that would validate it:

function validateSequence(x) {
  return !!x.reduce(function(a, v, i, arr){
    return (arr.length - 1 == i) ? a : a + (arr[i+1] - v) + ',';
  }, '').match(/^(\d+,)\1*$/);
}

for example what are the two !! before x.reduce and how does it work?

rlemon
  • 17,518
  • 14
  • 92
  • 123
Aaron Rabinowitz
  • 357
  • 2
  • 18

2 Answers2

2

The RegExp /^(\d+,)\1*$/ means

  1. ^ From the beginning of the string
  2. (\d+,) match any number of digits (0..9) followed by a comma ,. Remember this.
  3. \1 match everything that follows this if it is exactly the same as what we saw in 2
  4. If we've reached the end of the String, the pattern is a match

Next the following,

x.reduce(function(a, v, i, arr){ /*...*/}, ''); 
  1. Create '' as an initial condition
  2. On an Array x, iterate over every item calling the function with the following parameters
    • a accumulator, the previous returned value (or the initial condition for first invocation)
    • v the item at the current iteration
    • i the index at the current iteration
    • arr the Array .reduce was called on (i.e. x, the this of .reduce)

So what is return (arr.length - 1 == i) ? a : a + (arr[i+1] - v) + ',' doing?

Lets re-write it as an if..else and comment in what is happening

if (arr.length - 1 == i)   // if this is the last item in the array
    return a;              // return the accumulator (what we generated last invocation)
else                       // otherwise
    return a +             // return the accumulator AND
        (arr[i + 1] - v) + // the difference between this item and the next item AND
        ',';               // a comma

Finally, the last bit we need to understand is !!. This is just shorthand for converting

  • A truthy thing (e.g. any object [], non-empty string etc) to true
  • A falsy thing (e.g. null, RegExp did not match) to false

This is being applied to the result of the RegExp so it basically means, if we found a match return true, otherwise false.


This explained, it is a very convoluted way to do the following

function validateSequence(seq) {
    var delta = seq[1] - seq[0],
        i;
    // some `.length` test here?
    for (i = 2; i < seq.length; ++i)
        if (seq[i - 1] + delta !== seq[i])
            return false;
    return true;
}

I would not recommend using the method you provided.

Paul S.
  • 64,864
  • 9
  • 122
  • 138
  • S.so let me get this strait the what exactly is the accumulator its somehow the difference between previous and next item and is returned how come it stays the same even after in the termany operator(if else)it gets plused (arr[i + 1] - v) + ','; – Aaron Rabinowitz Nov 18 '15 at 20:21
  • 1
    @AaronRabinowitz The accumulator is the previous return value. E.g. if the last iteration `return`ed `"4,"`, the `a` in the current iteration is `"4,"`. If you then return `a + "6,"`, the `a` in the next iteration would therefore be `"4,6,"`. If we then had run out of items to iterate, `"4,6,"` would be the ultimate returned value of `.reduce` – Paul S. Nov 18 '15 at 21:11
1

!! is known as the "double-bang" or "not-not" operator and is used to coerce an object into a boolean. See What is the !! (not not) operator in JavaScript?

reduce is an enumerator. It will execute the callback once for each element in the array. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

The function is looping through the array and will return true only if the each successive element in the array increases by the same integer value over the previous one.

Community
  • 1
  • 1
Ryenski
  • 9,582
  • 3
  • 43
  • 47