1

What is the most pythonic way to sort a list of lists with a tie-breaker?

I can sort by sub-list length (longest to shortest):

>>> l = [['c'], ['a', 'b'], ['b', 'c'], ['a', 'b', 'c']]

>>> list(reversed(sorted(l, key=len)))
[['a', 'b', 'c'], ['b', 'c'], ['a', 'b'], ['c']]

But I want to preserve order when the lengths are equal, so the output I want is:

[['a', 'b', 'c'], ['a', 'b'], ['b', 'c'], ['c']]
ssjadon
  • 329
  • 3
  • 9
  • 1
    Related: [Is python's sorted() function guaranteed to be stable?](http://stackoverflow.com/questions/1915376/is-pythons-sorted-function-guaranteed-to-be-stable) – tobias_k Oct 24 '16 at 15:46

2 Answers2

5

Timsort (Python's built-in sorting algorithm) is stable, meaning it keeps the original order of elements with equal keys. However, you reversed the original order by using the reversed function.

If you want to reverse the resulting list and preserve the original order of elements comparing equal, use reverse=True:

In [3]: sorted(l, key=len, reverse=True)
Out[3]: [['a', 'b', 'c'], ['a', 'b'], ['b', 'c'], ['c']]
vaultah
  • 44,105
  • 12
  • 114
  • 143
  • 1
    Good answer, I pass `reverse` an argument to `sorted` because it's more efficient than reversing the output of sorted, but I'd not considered that the final result could be different – Chris_Rands Oct 24 '16 at 16:02
0

You could make a new list, paring each element with its position in the original list, then sort using that value as a secondary part of the key, and finally stripping the positions of for the final result.

Scott Hunter
  • 48,888
  • 12
  • 60
  • 101