Sort by Another List's Order
Problem
A shop sorts its stock codes by a preferred order from the marketing team. Given values and a list order of distinct codes, rearrange values so that codes appearing in order come first, grouped and in the same sequence as order, followed by every other code in ascending order. Both lists hold at most 1,000 items, every code in order also appears in values, and each code is between 0 and 1,000.
Examples
Input: values = [2, 3, 1, 3, 2, 4, 6, 7, 9, 2, 19], order = [2, 1, 4, 3, 9, 6]
Output: [2, 2, 2, 1, 4, 3, 3, 9, 6, 7, 19]
Why: 7 and 19 are not in order, so they go last in ascending order
Input: values = [28, 6, 22, 8, 44, 17], order = [22, 28, 8, 6]
Output: [22, 28, 8, 6, 17, 44]
Input: values = [5, 5], order = []
Output: [5, 5]
Why: edge case, with an empty order the result is a plain ascending sort
Hints
0 / 3
The codes are small integers, so you can count how many times each one appears instead of comparing them.
With the counts in hand, the output is just a walk: first through order, then through all codes from 0 upward.
For each code in order, emit it as many times as it was counted and set its count to 0. Then sweep 0 to 1,000 and emit whatever counts are left.
Solution
Because every code lies between 0 and 1,000, a counting array replaces comparisons entirely. One pass over values records how many copies of each code exist. Walking order then emits each preferred code the right number of times, and zeroing its count ensures it is not emitted again. The final sweep over all possible codes from low to high emits the leftovers in ascending order, which is exactly the tail the problem asks for. With k = 1,001 possible codes, time is O(n + k) and extra space is O(k).
def relative_sort(values, order, top=1000):
counts = [0] * (top + 1)
for v in values:
counts[v] += 1
out = []
for code in order: # preferred codes first, grouped
out += [code] * counts[code]
counts[code] = 0
for code in range(top + 1): # the rest, ascending
out += [code] * counts[code]
return out
print(relative_sort([2, 3, 1, 3, 2, 4, 6, 7, 9, 2, 19], [2, 1, 4, 3, 9, 6])) # -> [2, 2, 2, 1, 4, 3, 3, 9, 6, 7, 19]
print(relative_sort([28, 6, 22, 8, 44, 17], [22, 28, 8, 6])) # -> [22, 28, 8, 6, 17, 44]
print(relative_sort([5, 5], [])) # -> [5, 5]Stuck on the idea rather than the code? Counting Sort covers it.