pythonarrays

What does the below line of python code do to the input array?


Given

C=[4,3,2,5,6,6,8,7]

What happens to the array upon processing?

ind = range(len(C))
ind.sort(cmp = lambda i, j: C[j] - C[i])

Result

[6, 7, 4, 5, 3, 0, 1, 2]

Solution

  • This looks like an outdated way of writing a descending argsort - a routine for producing indices such that [C[i] for i in ind] == sorted(C, reverse=True). It relies on the cmp argument of list.sort, which was removed in Python 3 because it was confusing and inefficient for most use cases.

    Given a list ind, initialized as range(len(C)) (on Python 2, where range makes a list), this code would sort the elements of ind based on descending order of the values of the corresponding elements of C. (C would be unaffected.)

    On Python 3, this could instead be written as

    C = [4, 3, 2, 5, 6, 6, 8, 7]
    ind = list(range(len(C)))    # Python 3 needs an explicit conversion to list here
    ind.sort(key=lambda i: -C[i])
    

    or

    C = [4, 3, 2, 5, 6, 6, 8, 7]
    ind = list(range(len(C)))    # Python 3 needs an explicit conversion to list here
    ind.sort(key=lambda i: C[i], reverse=True)
    

    or

    C = [4, 3, 2, 5, 6, 6, 8, 7]
    # No explicit list call needed for this one
    ind = sorted(range(len(C)), key=lambda i: C[i], reverse=True)
    

    A Python 2-style comparator takes 2 arguments and returns an integer. The return value should be less than, equal to, or greater than 0 to indicate that the first argument should be considered less than, equal to, or greater than the second argument respectively.

    lambda i, j: C[j] - C[i] treats its arguments as indices into C, and the subtraction returns a negative, 0, or positive value if the second argument corresponded to an element of C less than, equal to, or greater than the element the first argument corresponded to. Thus, i is considered less than j according to this comparator if C[i] is greater than C[j].

    It would arguably be more clear to write the comparator as lambda i, j: cmp(C[j], C[i]), explicitly returning the result of comparing C[j] and C[i], rather than subtracting. Doing so is much less prone to sign confusion. But considering how old Python 2 is, hopefully you don't actually have to maintain any Python 2 code. For modernizing this code, you'd need to switch to a key function anyway.