This is some bad code, but illustrates the difficulty, futility, and pointlessness of implementing map/filter with Iterables.
Note that these are lazy (not eager). Nothing runs until the for..of
is called on an instance, etc.
class IterableWMapFilter<T> {
vals : T[]= [];
operations: Iterator<T>[] = []
constructor(intialVals: T[]) {
// add initial values
for(const v in intialVals){ // faster than for..of, in theory
this.vals.push(intialVals[v]);
}
}
add(v: any){
this.vals.push(v);
}
map(fn: (val: number) => any) : IterableWMapFilter<T> {
const ret = new IterableWMapFilter(this.vals.slice(0));
ret.operations = this.operations.concat(<any>{ // store new ref
next(value: number, done: boolean) {
if (done === true) {
return {done: true, value: null} as any;
}
return {done: false, value: fn(value)}
}
});
return ret;
}
filter(fn: (val: number) => any): IterableWMapFilter<T> {
const ret = new IterableWMapFilter(this.vals.slice(0));
ret.operations = this.operations.concat(<any>{ // store new ref
next(val: any, done: boolean) {
if (done === true) {
return {done: true, value: null} as any;
}
if (Boolean(fn(val))) {
return {done: false, value: val};
} else {
// we pass "ignore" to tell consumer to filter it out (not really ideal at all)
return {done: false, ignore: true};
}
}
});
return ret;
}
[Symbol.iterator](): Iterator<T> {
const next : any = () => {
if(this.vals.length < 1){
return {done: true, value: null};
}
let n : any = this.vals.shift(); // using Array.prototype.shift() is O(N), (Array is a bad queue)
for (let v of this.operations) {
const z = v.next(n);
if((z as any).ignore === true){
// ignore means its filtered out, so we get next value
return next();
}
n = z.value; // reset n with new val
}
return {done: false, value: n};
}
return {
next
}
}
}
const v = new IterableWMapFilter<number>([1,2,3])
.filter((v) => {
// console.log('v in filter:', v);
return v % 2 === 0;
})
.map(v => {
// console.log('v in map:', v);
return v + 10;
});
v.add(4);
v.add(5);
v.add(6);
for (let x of v) {
console.log('result:',x);
}