Home > Software design >  Rank elements in nested list without sorting list
Rank elements in nested list without sorting list

Time:10-20

Let's say I have a nested list:

list = [[10, 2, 8, 4], [12, 6, 4, 1], [8, 4, 3, 2], [9, 3, 4, 6]]

I want to rank the elements in the sublist against each other to create a new nested list with the rankings.

result = [[1, 4, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4], [1, 4, 3, 2]]

in the first sublist 10 would be 1st, 8 2nd, etc.

CodePudding user response:

As already mentioned in the comment, you can use numpy.argsort, using it twice gives you the rank for the values, which need to be subtracted from len of the sub list to rank from highest to lowest, you can use List-Comprehension to do it for all the sub lists.

>>> import numpy as np
>>> lst = [[10, 2, 8, 4], [12, 6, 4, 1], [8, 4, 3, 2], [9, 3, 4, 6]]
>>> [(len(sub)-np.argsort(sub).argsort()).tolist() for sub in lst]
[[1, 4, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4], [1, 4, 3, 2]]

You can even use 2D numpy array and negate the values, then directly call argsort twice on the resulting array, and finally add 1:

>>> (-np.array(lst)).argsort().argsort() 1

array([[1, 4, 2, 3],
       [1, 2, 3, 4],
       [1, 2, 3, 4],
       [1, 4, 3, 2]], dtype=int64)

CodePudding user response:

You can use scipy.stats.rankdata:

my_list = [[10, 2, 8, 4], [12, 6, 4, 1], [8, 4, 3, 2], [9, 3, 4, 6]]


from scipy.stats import rankdata
[list(len(l) 1-rankdata(l).astype(int)) for l in my_list]

output:

[[1, 4, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4], [1, 4, 3, 2]]

CodePudding user response:

Without numpy/scipy:

[[sorted(li, reverse=True).index(x) 1 for x in li] for li in data]

[[1, 4, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4], [1, 4, 3, 2]]

CodePudding user response:

Another solution with no external libraries, and with a better time complexity, just in case your sublists are a bit longer than 4 items (this has some overhead but I presume it is O(n log n) because of the call to sorted).

def rank_all(ls):
    result = []
    for subls in ls:
        pairs = sorted([(subls[j],j) for j in range(len(subls))], reverse=True)
        ranked = [0] * len(subls)
        for j,p in enumerate(pairs):
            ranked[p[1]]=j 1
        result.append(ranked)
    return result
  • Related