import { EqualityComparer, IEnumerable, IEnumerableFactory } from '../../types'; export function applyLeftJoinHeterogeneous( factory: IEnumerableFactory, first: Iterable, second: Iterable, firstKeySelector: (item: TFirst) => TKey, secondKeySelector: (item: TSecond) => TKey, firstSelector: (item: TFirst) => TResult, bothSelector: (a: TFirst, b: TSecond) => TResult, equalityComparer?: EqualityComparer ): IEnumerable { function* generator(): Generator { if (equalityComparer) { for (const firstItem of first) { const firstKey = firstKeySelector(firstItem); let matched = false; for (const secondItem of second) { if (equalityComparer(firstKey, secondKeySelector(secondItem))) { matched = true; yield bothSelector(firstItem, secondItem); } } if (!matched) { yield firstSelector(firstItem); } } } else { const secondKeyMap = new Map(); for (const secondItem of second) { const secondKey = secondKeySelector(secondItem); const currentMatches = secondKeyMap.get(secondKey); if (currentMatches !== undefined) { currentMatches.push(secondItem); } else { secondKeyMap.set(secondKey, [secondItem]); } } for (const firstItem of first) { const firstKey = firstKeySelector(firstItem); const secondMatches = secondKeyMap.get(firstKey); if (secondMatches !== undefined) { for (let i = 0; i < secondMatches.length; i++) { yield bothSelector(firstItem, secondMatches[i]); } } else { yield firstSelector(firstItem); } } } } return factory.createBasicEnumerable(generator); } export function applyLeftJoinHomogeneous( factory: IEnumerableFactory, first: Iterable, second: Iterable, keySelector: (item: TFirst) => TKey, firstSelector: (item: TFirst) => TResult, bothSelector: (a: TFirst, b: TFirst) => TResult, equalityComparer?: EqualityComparer ): IEnumerable { function* genrator(): Generator { if (equalityComparer) { for (const firstItem of first) { const firstKey = keySelector(firstItem); let matched = false; for (const secondItem of second) { if (equalityComparer(firstKey, keySelector(secondItem))) { matched = true; yield bothSelector(firstItem, secondItem); } } if (!matched) { yield firstSelector(firstItem); } } } else { const secondKeyMap = new Map(); for (const secondItem of second) { const secondKey = keySelector(secondItem); const currentMatches = secondKeyMap.get(secondKey); if (currentMatches !== undefined) { currentMatches.push(secondItem); } else { secondKeyMap.set(secondKey, [secondItem]); } } for (const firstItem of first) { const firstKey = keySelector(firstItem); const secondMatches = secondKeyMap.get(firstKey); if (secondMatches !== undefined) { for (let i = 0; i < secondMatches.length; i++) { yield bothSelector(firstItem, secondMatches[i]); } } else { yield firstSelector(firstItem); } } } } return factory.createBasicEnumerable(genrator); }