Skip to content

Instantly share code, notes, and snippets.

@ORESoftware
Last active December 24, 2022 09:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ORESoftware/28dd5bc2fb283591722e48e6d827a49c to your computer and use it in GitHub Desktop.
Save ORESoftware/28dd5bc2fb283591722e48e6d827a49c to your computer and use it in GitHub Desktop.

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);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment