An alternative is to use closures:
function makeCircular(arr) {
var current = 0;
return function() {
return arr[current++ % arr.length];
}
}
const a = ['A', 'B', 'C'];
let next = makeCircular(a);
// imprime A, B, C, A, B, C...
for(i = 0; i < 20; i++) {
console.log(next());
}
makeCircular(a)
receives an array and returns another function, which in turn returns, at each call, the next circular array value.
You can even create several closures different for the same array, and each maintains its individual state:
function makeCircular(arr) {
var current = 0;
return function() {
return arr[current++ % arr.length];
}
}
const a = ['A', 'B', 'C'];
let next = makeCircular(a);
let next2 = makeCircular(a);
console.log(next()); // A
console.log(next()); // B
console.log(next2()); // A
console.log(next()); // C
Only one detail: the internal counter (current
) may give problem if it reaches the value of Number.MAX_VALUE
:
function makeCircular(arr) {
var current = Number.MAX_VALUE; // começando em MAX_VALUE só pra mostrar o problema
return function() {
return arr[current++ % arr.length];
}
}
const a = ['A', 'B', 'C'];
let next = makeCircular(a);
// imprime C 20 vezes
for(i = 0; i < 20; i++) {
console.log(next());
}
In this case, you printed "C" 20 times, indicating that when you reach MAX_VALUE
, it can no longer increase the value (tested in Chrome and Firefox and the behavior was the same).
All right that according to documentation, the value of MAX_VALUE
is about 21024, which should be more than sufficient for most applications.
But if you want to avoid this - rare - situation, you can keep the value of current
always smaller than the array size:
function makeCircular(arr) {
var current = -1;
return function() {
current = (current + 1) % arr.length;
return arr[current];
}
}
const a = ['A', 'B', 'C'];
let next = makeCircular(a);
// imprime A, B, C, A, B, C...
for(i = 0; i < 20; i++) {
console.log(next());
}
I made a benchmark out of curiosity and really the difference in performance is drastic... See here. Anyway, I still think it’s a super interesting solution. A pity that the performance of iterators is still bad (and in view of what they do should be excellent). I hope that one day this will improve.
– Luiz Felipe