Skip to content

Instantly share code, notes, and snippets.

@duncanbeevers
Last active December 30, 2021 12:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save duncanbeevers/ea3cd1bbde2de0b8a9ed61a46be4563b to your computer and use it in GitHub Desktop.
Save duncanbeevers/ea3cd1bbde2de0b8a9ed61a46be4563b to your computer and use it in GitHub Desktop.
Sort collection with ranked scoring functions, minimal executions
const ReversedSymbol = Symbol('reversed');
type ScoreScalar = string | number | boolean;
type Score = ScoreScalar | [ScoreScalar, typeof ReversedSymbol];
export type ScoreFunction<T> = (item: T) => Score;
function getResult<T>(
scoreFns: readonly ScoreFunction<T>[],
itemResults: Map<T, [Score, boolean][]>,
item: T,
i: number
) {
const results = itemResults.get(item) || [];
if (i >= results.length) {
const score = scoreFns[i](item);
results[i] =
typeof score === 'boolean' ||
typeof score === 'number' ||
typeof score === 'string'
? [score, false]
: [score[0], score[1] === ReversedSymbol];
itemResults.set(item, results);
}
return results[i];
}
export function reverseScore(score: Score): Score {
return typeof score === 'boolean' ||
typeof score === 'number' ||
typeof score === 'string'
? [score, ReversedSymbol]
: score[0];
}
export function dangerouslySortByScores<T>(
items: T[],
...scoreFns: readonly ScoreFunction<T>[]
) {
const itemResults = new Map<T, ReturnType<typeof getResult>[]>();
return items.sort((a: T, b: T) => {
for (let i = 0; i < scoreFns.length; i++) {
const [scoreA, isReverseA] = getResult(scoreFns, itemResults, a, i);
const [scoreB, isReverseB] = getResult(scoreFns, itemResults, b, i);
if (scoreA !== scoreB) {
return (scoreA < scoreB ? -1 : 1) * (isReverseA || isReverseB ? -1 : 1);
}
}
return 0;
});
}
export function sortByScores<T>(
items: readonly T[],
...scoreFns: readonly ScoreFunction<T>[]
) {
return dangerouslySortByScores([...items], ...scoreFns);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment