Skip to content

Instantly share code, notes, and snippets.

@loilo
Last active June 27, 2022 10:10
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 loilo/132acc9d213e5e0b90939214947d6acd to your computer and use it in GitHub Desktop.
Save loilo/132acc9d213e5e0b90939214947d6acd to your computer and use it in GitHub Desktop.
Sort by Samples

Sort by Samples

A sorting function that takes an array of samples. All sortable items which occur in the samples will be arranged in the order they occur there, all other items will be appended to the end in their original order or sorted with an optional provided comparision algorithm.

This can be useful when the items to sort are not completely known, but there are some well-known ones that should come first:

const pages = [ 'About', 'Products', 'Home', 'Contact', 'Carreer' ]

// No idea what pages exist, but if "Home" and "About" exist, they should come first

// Other pages should be kept in their original order
[...pages].sort(sortBySamples([ 'Home', 'About' ]))
// [ 'Home', 'About', 'Products', 'Contact', 'Carreer' ]

// Other pages should be kept in their original order, but "Contact" should come last
[...pages].sort(sortBySamples([ 'Home', 'About' ], (a, b) => {
  if (a === 'Contact') {
    return 1
  } else if (b === 'Contact') {
    return -1
  } else {
    return 0
  }
}))
// [ 'Home', 'About', 'Products', 'Carreer', 'Contact' ]
function sortBySamples(samples, { getter = null, fallbackComparator = null } = {}) {
return (a, b) => {
const reducedA = getter?.(a) ?? a
const reducedB = getter?.(b) ?? b
const aIsSampled = samples.includes(reducedA)
const bIsSampled = samples.includes(reducedB)
if (aIsSampled && bIsSampled) {
return samples.indexOf(reducedA) - samples.indexOf(reducedB)
} else if (aIsSampled) {
return -1
} else if (bIsSampled) {
return 1
} else if (fallbackComparator) {
return fallbackComparator(a, b)
} else {
return 0
}
}
}
function sort_by_samples(
array $samples,
?callable $getter = null,
?callable $fallback_comparator = null
): callable {
return function ($a, $b) use ($samples, $getter, $fallback_comparator) {
$reduced_a = is_null($getter) ? $a : $getter($a);
$reduced_b = is_null($getter) ? $b : $getter($b);
$a_is_sampled = in_array($reduced_a, $samples);
$b_is_sampled = in_array($reduced_b, $samples);
if ($a_is_sampled && $b_is_sampled) {
return array_search($reduced_a, $samples) <=> array_search($reduced_b, $samples);
} else if ($a_is_sampled) {
return -1;
} else if ($b_is_sampled) {
return 1;
} else if ($fallback_comparator) {;
return $fallback_comparator($a, $b);
} else {
return 0;
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment