You could group the items by the second value of each tuple using itertools.groupby, sort groupings by the first item in each group, then flatten the result with itertools.chain.from_iterable:
from operator import itemgetter
from itertools import groupby, chain
def relative_sort(Input):
return list(
chain.from_iterable(
sorted(
(
tuple(g)
for _, g in groupby(
sorted(Input, key=itemgetter(1)), key=itemgetter(1)
)
),
key=itemgetter(0),
)
)
)
Output:
>>> relative_sort([("M", 19), ("H", 19), ("A", 25)])
[('A', 25), ('M', 19), ('H', 19)]
>>> relative_sort([("B", 19), ("B", 25), ("M", 19), ("H", 19), ("A", 25)])
[('B', 19), ('M', 19), ('H', 19), ('B', 25), ('A', 25)]
>>> relative_sort([("A", 19), ("B", 25), ("M", 19), ("J", 30), ("H", 19)])
[('A', 19), ('M', 19), ('H', 19), ('B', 25), ('J', 30)]
("J", 30)sort in your example, since it's betweenHandMin alphabetical order? If("Z", 25)was added, how would it effect things? Does it matter if tuples containing the same number are adjacent to each other in the input, or should the result be the same as long as they're in the same order relative to each other, regardless of where other items (with other numbers) are?