pythonsortingstability

Is sort unstable in Python when using cmp_to_key?


I want to sort the positive values in a list of numbers, but leave the negative values where they are.

I tried to create a custom comparison function that says that negative numbers are equal to any other number, but this does not seem to work as I expected. Here is the code:

import functools

def my_cmp(a, b):
    if (a < 0) or (b < 0):
        return 0
    elif a < b:
        return -1
    else:
        return 1

x = [2, 7, 5.2, -7, -2, 10, 30, 13.1, -3, 14, 9, 15]

print(sorted(x, key=functools.cmp_to_key(my_cmp)))

The code returns:

[2, 5.2, 7, -7, -2, 9, 10, 13.1, 14, 30, -3, 15]

But I expected

[2, 5.2, 7, -7, -2, 10, 13.1, 30, -3, 9, 14, 15]

since Python's sort is supposed to be stable. Is this not working because the negative numbers are equal to any other number?

Is there a better way to this without using loops? I can do this by breaking up the list and sorting each part corresponding to the positive numbers, but I would like a more elegant way to this.


Solution

  • Splitting the list into discrete parts based on sign and sorting those is probably easiest. Here's a way using itertools.groupby

    from itertools import chain, groupby
    
    x = [2, 7, 5.2, -7, -2, 10, 30, 13.1, -3, 14, 9, 15]
    
    groups = groupby(x, key=lambda a: a > 0)
    res = list(chain.from_iterable(sorted(g) if k else g for k, g in groups))
    
    print(res)
    # [2, 5.2, 7, -7, -2, 10, 13.1, 30, -3, 9, 14, 15]