4
\$\begingroup\$

I'm writing a JavaScript function for an array, based on a geographic sequence. \$[1, 2, 4, 8, 16]\$, etc.

This function needs to populate the next number in the sequence $$item_n = item_{n-1} * 2$$ If there are more than \$10\$ items in the array, remove the first (smallest) number.

If the array reaches \$2^{15}\$ (no idea what this is), reset the array to its original contents - \$[1, 2, 4, 8, 16]\$.

I have it working, but I feel this could be written more efficiently...

updateSequence() {
  var sequence = this.get("geometricSequence");

  // Modify the sequence here
  function* values(sequence) {
    for (let prop of Object.keys(sequence)) 
    yield sequence[prop];
  }
  let arr = Array.from(values(sequence));

  const lastIndex = arr.length - 1;
  const lastValue = parseInt(arr[lastIndex]) * 2;
  arr.push(lastValue);
  if (lastIndex > 9) {
    arr.slice(0, 1);
  }
  if (lastValue > 32768) {
    arr = [1, 2, 4, 8, 16];
  }
  this.set('geometricSequence', arr);
}
\$\endgroup\$
  • \$\begingroup\$ Could you include the code for this.get("geometricSequence") and an example how this data looks? \$\endgroup\$ – dfhwze Sep 14 at 20:09
2
\$\begingroup\$

This will be cleaner if you implement it as a pure function, which takes the sequence as an argument. You can make [1, 2, 4, 8, 16] a default value for that argument, so that you can start the sequence with nothing. Taking this approach, the function simplifies to:

function updateSequence(arr = updateSequence.default) {
  const last = arr[arr.length-1]
  if (last == 32768) return updateSequence.default

  const ret = arr.concat(last * 2)
  return ret.length > 10 ? ret.slice(1) : ret
}
updateSequence.default = [1, 2, 4, 8, 16]

You can test that it works like this:

// test it
var arr = updateSequence()
for (i=0; i<15; i++) {
  console.log(arr)
  arr = updateSequence(arr)
}

which prints the following:

[ 1, 2, 4, 8, 16, 32 ]
[ 1, 2, 4, 8, 16, 32, 64 ]
[ 1, 2, 4, 8, 16, 32, 64, 128 ]
[ 1, 2, 4, 8, 16, 32, 64, 128, 256 ]
[ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]
[ 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 ]
[ 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048 ]
[ 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 ]
[ 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 ]
[ 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 ]
[ 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 ]
[ 1, 2, 4, 8, 16 ]
[ 1, 2, 4, 8, 16, 32 ]
[ 1, 2, 4, 8, 16, 32, 64 ]
[ 1, 2, 4, 8, 16, 32, 64, 128 ]
\$\endgroup\$
1
\$\begingroup\$

Since obj.get("geometricSequence"); presumably already contains an array, you can skip the whole shenanigans with the iterator and directly work on that. Also, if you change the order of the if statements at the end you can save some work by not doing slices on an array you eventually gonna replace later anyway. So:

updateSequence() {
  let arr = this.get("geometricSequence");

  const lastIndex = arr.length - 1;
  const lastValue = parseInt(arr[lastIndex]) * 2;

  arr.push(lastValue);

  if (lastValue > 32768)
    arr = [1, 2, 4, 8, 16];
  else if (lastIndex > 9)
    arr.slice(0, 1);

  this.set('geometricSequence', arr);
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.