1

I know my question seems confusing, but let's say I have the following list:

List1 = [15,16,1,2]

So, the position of [ 15, 16, 1, 2 ] is [ 0, 1, 2, 3 ].

What I am looking for is a result list containing the position from the smallest number of list1 to biggest.

Result List = [2,3,0,1]

I don't exactly know the most efficient way to do it in Python.

Izalion
  • 708
  • 4
  • 11

2 Answers2

3

Use enumerate and sorted with a custom key using a lambda expression:

List1 = [15,16,1,2]

v  = [i for i,_ in sorted(enumerate(List1), key=lambda x:x[1])]

print(v)

Output:

[2,3,0,1]

enumerate(List1) produces tuples of (index, value) that are sorted based on the value and then only the index is used to create the resulting list.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • 1
    There are shorter and better-performing solutions that doesn't require the creation of extra lists (of tuples) besides of the output one. See my answer. – janluke Nov 30 '20 at 16:27
2

What you want is called argsort in some libraries. In mathematical terms, you want a "permutation" (look it up on wikipedia) that when applied to the input list gives a sorted list.

The best way to do it in Python is the following:

def argsort(lst):
    return sorted(range(len(lst)), key=lst.__getitem__)

lst = [15,16,1,2]
print(argsort(lst))
# print: [2, 3, 0, 1]

This is how it works. Instead of sorting the values in lst, you sort the indexes (range(0, len(lst))) using the corresponding lst values as "keys". Keep in mind that lst.__getitem__(i) is just equivalent to lst[i].

EDIT: for people new to Python and unfamiliar with the "key" argument and the magic methods of Python (those written like __this__), this may be intimidating. A more friendly versione could be:

def argsort(lst):
    indexes = range(len(lst))
    return sorted(indexes, key=lambda i: lst[i])
janluke
  • 1,567
  • 1
  • 15
  • 19
  • Performs better then mine if memory and space is _really_ important. Nice one - still think mine is easier to grasp :D) – Patrick Artner Nov 30 '20 at 16:41
  • 1
    I don't agree :). This performs better both in time and space without adding extra complexity or code. Your solution is literally doing the same thing (the key argument of sorted is the same) adding two extra unnecessary steps: creation of tuples (index, value) and extraction of indexes from the sorted list of tuples. I agree that the use of lst.__getitem__ plus the fact that I didn't give a name ("indexes") to the range may be intimidating for people new to Python. I'll expand my answer... – janluke Nov 30 '20 at 17:16
  • Yes first one is easier to understand the logic.. but I ended up using the second since since I'm dealing with a relative big amount of data. Thank you both guys! – Izalion Dec 01 '20 at 08:03