Tuesday, 31 December 2019

Aggregate in Typescript

I have implemented Aggregate method in my Linq library written for Typescript.

if (!Array.prototype.Aggregate) {
  Array.prototype.Aggregate = function <T>(accumulator: any, currentValue: any, reducerFunc: (accumulator: any, currentValue: any) => any): any {
    //debugger
    if (reducerFunc === undefined || reducerFunc === null) {
      reducerFunc = (accumulator, currentValue) => accumulator + currentValue;
    }
    let result = this.reduce(reducerFunc);
    return result;
  }
}

if (!Array.prototype.AggregateSelect) {
  Array.prototype.AggregateSelect = function <T>(property: (keyof T), accumulator: any, currentValue: any, reducerFunc: (accumulator: any, currentValue: any) => any): any {
    //debugger
    if (reducerFunc === undefined || reducerFunc === null) {
      reducerFunc = (accumulator, currentValue) => accumulator + currentValue;
    }
    //debugger
    let result = this.Select(property).map(n => n[property]).reduce(reducerFunc);
    return result;
  }
}

Here are some Jasmine tests for these two methods - note that I also support setting the initial value.
  it('can aggregate items to expected result using Aggregate on array of items of numbers', () => {
    let someNums = [1, 2, 3, 4];
    let result = someNums.Aggregate(0, 0, null);
    expect(result).toBe(10);
  });

  it('can aggregate items and project to expected result using AggregateSelect on array of items of objects', () => {
    let someArray: any[] = [];
    someArray.push(<SomeClass>{ Name: "Foo", Num: 1 });
    someArray.push(<SomeClass>{ Name: "FooBaz", Num: 4 });
    someArray.push(<SomeClass>{ Name: "AllyoBaze", Num: 7 });
    let result = someArray.AggregateSelect<SomeClass>("Num", 0, 0, null);
    expect(result).toBe(12);
  });

  it('can aggregate once more items and project to expected result using AggregateSelect on array of items of objects with accumulator value set initially', () => {
    let someArray: Student[] = [];
    someArray.push(<Student>{ StudentID: 1, StudentName: "John", Age: 13 });
    someArray.push(<Student>{ StudentID: 2, StudentName: "Moin", Age: 21 });
    someArray.push(<Student>{ StudentID: 3, StudentName: "Bill", Age: 18 });
    someArray.push(<Student>{ StudentID: 4, StudentName: "Ram", Age: 20 });
    someArray.push(<Student>{ StudentID: 5, StudentName: "Ron", Age: 15 });
    let result = someArray.AggregateSelect<Student>("StudentName", "Student Names: ", 0, (a, b) => a + "," + b);
    expect(result).toBe("John,Moin,Bill,Ram,Ron");
  });

My interface definition is growing everytime for my Linq Library! Here is how it looks now:

export { } //creating a module of below code
declare global {
  type predicate<T> = (arg: T) => boolean;
  type sortingValue<T> = (arg: T) => any;
  interface Array<T> {
    FirstOrDefault<T>(condition: predicate<T>): T;
    LastOrDefault<T>(condition: predicate<T>): T;
    Where<T>(condition: predicate<T>): T[];
    Count<T>(): number;
    CountBy<T>(condition: predicate<T>): number;
    Select<T>(...properties: (keyof T)[]): any[];
    GroupBy<T>(groupFunc: (arg: T) => string): any[];
    EnumerableRange(start: number, count: number): number[];
    Any<T>(condition: predicate<T>): boolean;
    All<T>(condition: predicate<T>): boolean;
    MaxSelect<T>(property: (keyof T)): any;
    MinSelect<T>(property: (keyof T)): any;
    Average<T>(): number;
    AverageSelect<T>(property: (keyof T)): number;
    Max(): any;
    Min(): any;
    Sum(): any;
    Distinct<T>(): T[];
    DistinctBy<T>(property: (keyof T)): any;
    SumSelect<T>(property: (keyof T)): any;
    Intersect<T>(otherArray: T[]): T[];
    IntersectSelect<T>(property: (keyof T), otherArray: T[]): T[];
    MinSelect<T>(property: (keyof T)): any;
    OrderBy<T>(sortMember: sortingValue<T>): T[];
    OrderByDescending<T>(sortMember: sortingValue<T>): T[];
    ThenBy<T>(sortMember: sortingValue<T>): T[];
    OfType<T>(compareObject: T): T[];
    SequenceEqual<T>(compareArray: T): boolean;
    Take<T>(count: number): T[];
    TakeWhile<T>(condition: predicate<T>): T[];
    SkipWhile<T>(condition: predicate<T>): T[];
    Skip<T>(count: number): T[];
    defaultComparerSort<T>(x: T, y: T);
    ElementAt<T>(index: number);
    ElementAtOrDefault<T>(index: number);
    Aggregate<T>(accumulator: any, currentValue: any, reducerFunc: (accumulator: any, currentValue: any) => any): any;
    AggregateSelect<T>(property: (keyof T), accumulator: any, currentValue: any, reducerFunc: (accumulator: any, currentValue: any) => any): any;
  }
}


Share this article on LinkedIn.

1 comment:

  1. Do this hack to drop 2 lbs of fat in 8 hours

    At least 160k women and men are losing weight with a easy and secret "water hack" to burn 1-2 lbs each and every night while they sleep.

    It's very simple and it works with anybody.

    Just follow these easy step:

    1) Hold a clear glass and fill it up half full

    2) Now do this crazy hack

    so you'll be 1-2 lbs lighter the next day!

    ReplyDelete