import { Collector, BaseCollector, Supplier, collect } from "../collector"; import { toArray } from "./toArray"; export interface Mapper { ( value : T ) : U; } export class GroupingByCollector> extends BaseCollector, Map> { protected mapper : Mapper; protected supplier : Supplier; protected collector : Collector; constructor ( mapper : Mapper, supplier : Supplier, collector : Collector ) { super(); this.mapper = mapper; this.supplier = supplier; this.collector = collector; } supply () : Map { return new Map(); } accumulate ( container : Map, item : T ) : void { const key = this.mapper( item ); if ( !container.get( key ) ) { const subContainer = this.collector.supply(); container.set( key, subContainer ); this.collector.accumulate( subContainer, item ); } else { this.collector.accumulate( container.get( key ), item ); } } combine ( container1 : Map, container2 : Map ) : Map { for ( let [ key, value ] of container2 ) { container1.set( key, this.collector.combine( container1.get( key ), value ) ); } return container1; } finish ( container : Map ) : Map { let finished = this.supplier(); for ( let [ key, value ] of container ) { finished.set( key, this.collector.finish( value ) ); } return finished; } } export function groupingBy ( mapper : ( item : T ) => K ) : Collector, Map>; export function groupingBy ( mapper : ( item : T ) => K, collector : Collector ) : Collector, Map>; export function groupingBy> ( mapper : ( item : T ) => K, supplier : Supplier, collector : Collector ) : Collector, Map>; export function groupingBy> ( mapper : ( item : T ) => K, supplier ?: Supplier | Collector, collector ?: Collector ) : Collector { if ( !supplier && !collector ) { return groupingBy( mapper, () => new Map(), toArray() ); } else if ( !collector ) { return groupingBy( mapper, () => new Map(), supplier as Collector ); } return new GroupingByCollector( mapper, supplier as Supplier, collector ); }