import { EqualityComparer, IEnumerable, IEnumerableFactory } from '../../types'; import { getIterableGenerator } from '../../utilities/utilityFunctions'; export function applyGroupJoin( factory: IEnumerableFactory, outer: Iterable, inner: Iterable, outerKeySelector: (item: TOuter) => TKey, innerKeySelector: (item: TInner) => TKey, resultSelector: (item: TOuter, inner: IEnumerable) => TResult, equalityComparer?: EqualityComparer ): IEnumerable { function* generator(): Generator { if (equalityComparer) { for (const outerItem of outer) { const outerKey = outerKeySelector(outerItem); const inners = factory .createBasicEnumerable(getIterableGenerator(inner)) .where(innerItem => equalityComparer(outerKey, innerKeySelector(innerItem))); yield resultSelector(outerItem, inners); } } else { const innerMap = new Map(); for (const innerItem of inner) { const key = innerKeySelector(innerItem); const curr = innerMap.get(key); if (curr !== undefined) { curr.push(innerItem); } else { innerMap.set(key, [innerItem]); } } for (const outerItem of outer) { const key = outerKeySelector(outerItem); const innersToJoin = innerMap.get(key); yield resultSelector(outerItem, factory.createBasicEnumerable(getIterableGenerator(innersToJoin ?? []))); } } } return factory.createBasicEnumerable(generator); }