Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to replace numbers with order in (python) list

I have a list containing integers and want to replace them so that the element which previously contained the highest number now contains a 1, the second highest number set to 2, etc etc.

Example: [5, 6, 34, 1, 9, 3] should yield [4, 3, 1, 6, 2, 5].

I personally only care about the first 9 highest numbers by I thought there might be a simple algorithm or possibly even a python function to do take care of this task?

Edit: I don't care how duplicates are handled.

like image 495
Max Matti Avatar asked Dec 01 '22 12:12

Max Matti


2 Answers

A fast way to do this is to first generate a list of tuples of the element and its position:

sort_data = [(x,i) for i,x in enumerate(data)]

next we sort these elements in reverse:

sort_data = sorted(sort_data,reverse=True)

which generates (for your sample input):

>>> sort_data
[(34, 2), (9, 4), (6, 1), (5, 0), (3, 5), (1, 3)]

and nest we need to fill in these elements like:

result = [0]*len(data)
for i,(_,idx) in enumerate(sort_data,1):
    result[idx] = i

Or putting it together:

def obtain_rank(data):
    sort_data = [(x,i) for i,x in enumerate(data)]
    sort_data = sorted(sort_data,reverse=True)
    result = [0]*len(data)
    for i,(_,idx) in enumerate(sort_data,1):
        result[idx] = i
    return result

this approach works in O(n log n) with n the number of elements in data.

A more compact algorithm (in the sense that no tuples are constructed for the sorting) is:

def obtain_rank(data):
    sort_data = sorted(range(len(data)),key=lambda i:data[i],reverse=True)
    result = [0]*len(data)
    for i,idx in enumerate(sort_data,1):
        result[idx] = i
    return result
like image 114
Willem Van Onsem Avatar answered Dec 05 '22 06:12

Willem Van Onsem


Another option, you can use rankdata function from scipy, and it provides options to handle duplicates:

from scipy.stats import rankdata

lst = [5, 6, 34, 1, 9, 3]
rankdata(list(map(lambda x: -x, lst)), method='ordinal')
# array([4, 3, 1, 6, 2, 5])
like image 39
Psidom Avatar answered Dec 05 '22 05:12

Psidom