import { Comparer, EqualityComparer } from '../types'; export function getIterableGenerator(src: Iterable): () => Generator { return Array.isArray(src) || typeof src === 'string' ? function* (): Generator { for (let i = 0; i < src.length; i++) { yield src[i]; } } : function* (): Generator { for (const item of src) { yield item; } }; } export function getKeySelectorAndComparer( overrideKeySelector: ((item: TSource) => TKey) | null, others: (Iterable | ((item: TSource) => TKey) | EqualityComparer)[] ): [others: Iterable[], keySelector: (item: TSource) => TKey, equalityComparer?: EqualityComparer] { const passedKeySelector = typeof overrideKeySelector === 'function'; const equalityComparer = typeof others[others.length - (passedKeySelector ? 1 : 2)] === 'function' ? (others.pop() as EqualityComparer) : undefined; const keySelector = overrideKeySelector ?? (others.pop() as (item: TSource) => TKey); const isIterableArray = ( arr: (Iterable | ((item: TSource) => TKey) | EqualityComparer)[] ): arr is Iterable[] => arr.every(x => Symbol.iterator in Object(x)); if ( typeof keySelector !== 'function' || (equalityComparer !== undefined && typeof equalityComparer !== 'function') || others.length === 0 || !isIterableArray(others) ) { throw new Error('Invalid use of overloads.'); } return [others, keySelector, equalityComparer]; } export function toKeyMap(src: Iterable, keySelector: (item: T) => TKey): Map { const map = new Map(); for (const item of src) { const key = keySelector(item); const curr = map.get(key); if (curr !== undefined) { curr.push(item); } else { map.set(key, [item]); } } return map; } export function* orderByGenerator( src: Iterable, ascending: boolean, selector: (item: TSource) => TKey, comparer?: Comparer ): Generator { const map = toKeyMap(src, selector); const sortedKeys = [...map.keys()].sort((a, b) => { if (comparer) { return comparer(a, b); } if (a > b) { return 1; } else if (a < b) { return -1; } else { return 0; } }); if (ascending) { for (let i = 0; i < sortedKeys.length; i++) { const items = map.get(sortedKeys[i]); yield items ?? []; } } else { for (let i = sortedKeys.length - 1; i >= 0; i--) { const items = map.get(sortedKeys[i]); yield items ?? []; } } }