✨Sequence
finite/infinite iterable of numbers
JS⟩ iteration ⟩ iterable ⟩ custom ⟩ Sequence
💾replit:(iterable) Sequence
// ⭐️ Sequence (iterable class)
//
// use cases:
// new Sequence() // 0, 1, 2, 3 ... (infinite)
// -------------------------------------------------------
class Sequence {
// 🔸 custom class type name
get [Symbol.toStringTag]() { return 'Sequence' }
// init
constructor({
start = 0,
step = 1, // step between numbers
end = undefined, // end of sequence
terms = undefined, // how many terms the sequence has
}={}) {
this.start = start;
this.step = step;
this.end = end; // ⭐️ ignored if `this.terms` is explicitly defined.
this.terms = terms; // ⭐️ `this.terms` has higher priority than `this.end`
// finite or infnite sequence
this.isInfinite = (this.end === undefined) && (this.terms === undefined);
this.isFinite = !this.isInfinite;
// ⭐️ if finite, calculate the correct number of terms,
// hence, `this.terms` is always defined in this case.
if (this.isFinite) {
// - if `this.terms` is defined, `this.end` is ignored.
// (the only use of `end` is to calculate the nubmer of terms, if it's not already defined)
// - if `this.terms` is not defined, `this.end` MUST be defined.
// (we calculate the number of terms from `start, end, step`.)
if (this.terms === undefined) {
this.terms = Math.max(0, Math.floor((this.end - this.start) / this.step + 1));
}
}
}
// 🔸 "make-iterator" method
[Symbol.iterator]() {
let counter = 0;
let currentValue = this.start;
// ⭐️ return the iterator
return { // new "iterator" object
// -------------------------------------------------
// ⭐️⭐️⭐️ arrow function as method ⭐️⭐️⭐️
// -------------------------------------------------
//
// ⭐️ in the body of following next(), return() methods:
// ❗ `this` does NOT refer to the new "iterator" object itself❗
// ❗ `this` === the `Sequence` object in the outer context❗
// 🔸 next iteration result (❗arrow function as method❗)
next: () => {
// if finite, check `this.terms` (because it's always properly defined)
// otherwise, always return the iteration result.
if (this.isFinite ? counter < this.terms : true) {
const result = { value: currentValue };
currentValue += this.step;
counter += 1;
return result; // return iteration result
}
// the iteration is done
return { done: true };
},
// 🔸 clean up when iteration stops prematurely
return: () => {
console.log(`${this}: cleaning up...`);
return { done: true }; // ⭐️ can't omit this result object although it's ignored.
}
} // end: return iterator
} // end: "make-iterator" method
} // end: class Sequence
// odd numbers: 1, 3, 5, 7, 9 ... (infinite)
for (const n of new Sequence({start: 1, step: 2})) {
if ( n > 7 ) break; // ⭐️ iteration stops prematurely
console.log(n); // ⭐️ 1, 3, 5, 7 (stops at 9)
} // ⭐️ [object Sequence]: cleaning up...
// destructuring sequence: 0, 1, 2, 3 ... (infinite)
const [a, b, c] = new Sequence(); // ⭐️ iteration stops prematurely
// ⭐️ [object Sequence]: cleaning up...
// log
a, b, c, // 0, 1, 2
// by default: start = 0, step = 1
[...new Sequence({terms: 5})], // [ 0, 1, 2, 3, 4 ]
[...new Sequence({end: 5})], // [ 0, 1, 2, 3, 4, 5 ]
[...new Sequence({terms: 5, start: 1})], // [ 1, 2, 3, 4, 5 ]
[...new Sequence({terms: 5, step: -1})], // [ 0, -1, -2, -3, -4 ]
[...new Sequence({terms: 5, end: 1})], // [ 0, 1, 2, 3, 4 ] (⭐️ `terms` defined, `end` ignored❗)
[...new Sequence({start: 5, end: 1})], // [ ] (⭐️ `terms` undefined, `end` respected❗)
[...new Sequence({start: 5, end: 1, step: -1})], // [ 5, 4, 3, 2, 1 ]
similar objects:
*integers() - non-negative integers. ()
Last updated