Python Forum

Full Version: How to sort a list with duplicates and return their unique indices.
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Given a list:

lst = [48,52,35,35,44,35]
I want to sort the list in descending order, so I use this:


sortedlst = sorted(slst, reverse = True)
I also want the original index in a sorted position as well. Like this:

sortedlstindx = [1,0,4,2,3,5]
for that I use this code:

sortedindx = [elem.index(lst) for elem in sorted(lst, reverse = True)]
The result I got is this:

sortedindx = [1,0,4,2,2,2]
How can I modify the code to give the result I want?
It's a shame I cannot use dict or set to help with this problem. No libraries import either sadly.
You could use built-in enumerate function to capture indices:

>>> print(*enumerate(lst))
(0, 48) (1, 52) (2, 35) (3, 35) (4, 44) (5, 35)
You can provide key function to sorted so that it sorts values, not indices:

>>> print(sorted(enumerate(lst), key=lambda i: i[1], reverse=True))
[(1, 52), (0, 48), (4, 44), (2, 35), (3, 35), (5, 35)]
Then you can use built-in zip for row-to-columns:

>>> print(*zip(*sorted(enumerate(lst), key=lambda i: i[1], reverse=True)))
(1, 0, 4, 2, 3, 5) (52, 48, 44, 35, 35, 35)
You can unpack it right away:

>>> indices, values = zip(*sorted(enumerate(lst), key=lambda i: i[1], reverse=True))
>>> indices
(1, 0, 4, 2, 3, 5)
>>> values
(52, 48, 44, 35, 35, 35)
He wanted unique elements.

lst = [48,52,35,35,44,35]


def unique_sort_index(sequence, reverse=False):
    unique = sorted(set(sequence), reverse=reverse)
    for element in unique:
        yield sequence.index(element)


def unique_sort_index2(sequence, reverse=False):
    seen = set()
    for index, element in sorted(enumerate(sequence), key=lambda x: x[1]):
        if element not in seen:
            seen.add(element)
            yield index


print("unique_sort_index")
for idx in unique_sort_index(lst):
    print(idx, lst[idx])

print("\nunique_sort_index2")
for idx in unique_sort_index2(lst):
    print(idx, lst[idx])
Output:
unique_sort_index 2 35 4 44 0 48 1 52 unique_sort_index2 2 35 4 44 0 48 1 52
I think DeaD_EyE is not interpreting the question correctly. I do not think "unique" means that the lst should be pared down to only contain unique values. I think the problem is the way the index sort was done returned non-unique values. The problem is caused by using "index" which returns the first match, not the index of the element.

To solve the problem, create a list of index values, and sort these using a key that references the original list. This is what perfingo did with the index, value tuples. Another way to do the same thing is create a separate list of index values and sort the index list using a key that references the original list.
lst = [48,52,35,35,44,35]
index = range(len(lst))
sorted_index = sorted(index, key=lambda i: lst[i])
print(sorted_index)
I like perfingo's method because it produces the sorted list and the sorted index list at the same time. I would use that if I needed both results. If I only needed the sorted index list I might use the separate array.

You could also do this with numpy's argsort()
import numpy as np

lst = np.array([48,52,35,35,44,35])
print(lst.argsort())