Problem
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
itemn=itemn−1∗2
If there are more than 10 items in the array, remove the first
(smallest) number.If the array reaches 215 (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);
}
Solution
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 ]
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);
}