Boosted_d16
Boosted_d16

Reputation: 14082

Basic Python: Rank items in list

I have a list:

[55, 41, 45, 43, 60, 47, 33, 70, 42, 42, 44]

I would like to create a new list which ranks these items in the order they are:

Expected Output:

[7, ,2 ,9 ,10, 4, 11, 3, 6, 1, 5, 8]

Tried these 3 version of the func but its not working properly, not sure why?

def argsort(seq):

    #return sorted(range(len(seq)), key = seq.__getitem__)

    #return [i for (v, i) in sorted((v, i) for (i, v) in enumerate(seq))]

    return [x for x,y in sorted(enumerate(seq), key = lambda x: x[1])] 

returns:

[6, 1, 8, 9, 3, 10, 2, 5, 0, 4, 7]

Upvotes: 6

Views: 10286

Answers (1)

inspectorG4dget
inspectorG4dget

Reputation: 113975

Let's come up with a more precise definition of what you are after:

Given a list L of numbers, create a list M that contains the valid indices of L, such that M[i] is the index at which the ith element of L occurs, when sorted. Present M as if the first element of L occurs at index 1.

Now, there are two ways of the valid indices of a list:

  1. range(len(L)): gives a sequence of numbers 0... len(L)-1
  2. enumerate(L): gives a sequence of tuples (0, L[0])... (len(L)-1, L[len(L)-1])

Since you want to operate under the assumption that list indices start at 1 (when in fact they start at 0 in python), we need to do a little off-setting

  1. range(len(L)) becomes `range(1, len(L)+1)
  2. enumerate(L) becomes enumerate(L, 1) (the optional argument tells enumerate to start numbering at 1)

Since we need the list items as well, let's use enumerate, rather than use range and do a lookup (I personally prefer this method, though both are valid)

So now, we can get a list of tuples, in which each tuple contains the index of an element in L and the corresponding element in L. We need to sort this by the elements themselves. This can be done with a call to sorted, with the optional key argument explaining that we should sort by the second element of the tuple (operator.itemgetter(1) says exactly this).

Once we have a sorted list of such tuples, all we need to do is extract the first element of each tuple (the index in L), we can use the list-comprehension [i[0] for i in mylist], or equivalently [operator.itemgetter(0)(t) for t in mylist]

Putting all these elements together, we get the following

In [138]: L = [55, 41, 45, 43, 60, 47, 33, 70, 42, 42, 44]

In [139]: [operator.itemgetter(0)(t) for t in sorted(enumerate(L,1), key=operator.itemgetter(1))]
Out[139]: [7, 2, 9, 10, 4, 11, 3, 6, 1, 5, 8]

Upvotes: 8

Related Questions