import { Collector, BaseCollector } from "../collector"; import { Mapper } from "../collections/groupingBy"; import { toArray } from "../collections/toArray"; export interface DistinctContainer { keys : Map; items: [U, T][]; } export class DistinctCollector extends BaseCollector, R> { protected keyer : Mapper; protected collector : Collector; constructor ( keyer : Mapper, collector : Collector ) { super(); this.keyer = keyer; this.collector = collector; } supply () : DistinctContainer { return { keys: new Map(), items: [] } } accumulate ( container : DistinctContainer, item : T ) : void { const key = this.keyer( item ); if ( !container.keys.has( key ) ) { container.keys.set( key, container.items.length ); container.items.push( [ key, item ] ); } } combine ( container1 : DistinctContainer, container2 : DistinctContainer ) : DistinctContainer { const keys = new Map( container1.keys ); const items = container1.items.slice(); for ( let [ key, item ] of container2.items ) { if ( !keys.has( key ) ) { keys.set( key, items.length ); items.push( [ key, item ] ); } } return { keys, items }; } finish ( container : DistinctContainer ) : R { const subContainer = this.collector.supply(); for ( let [ _, item ] of container.items ) { this.collector.accumulate( subContainer, item ); } return this.collector.finish( subContainer ); } } export function distinct () : Collector, T[]>; export function distinct ( keyer : Mapper ) : Collector, T[]>; export function distinct ( keyer : Mapper, collector ?: Collector ) : Collector, R>; export function distinct ( keyer ?: Mapper, collector ?: Collector ) : Collector, R | T[]> { return new DistinctCollector( keyer || ( x => x ), collector || toArray() as any ); }