I need to sort a python list but the sort should not alter the index the elements had before the sort. There's a function called asort for this in php, but how to do it in python? Is there such a method? If not, how to do it in fewer line?
For instance, take following example:
$a = [1, 5, 2, 4];
print_r($a);
asort($a);
print_r($a);
Output will be:
Array
(
[0] => 1
[1] => 5
[2] => 2
[3] => 4
)
Array
(
[0] => 1
[2] => 2
[3] => 4
[1] => 5
)
Here 5 still has index 1 after asort
but it has been sorted to the end.
I do have my own solution, which is: Create the indices as a list of integers. Then use [List Length] and [Series] to create this list. Then, sort both numeric values and indices synchronously, i.e. using the same Sort component. Although, this is not exactly what asort()
does, but pretty close.
Is there a better way to do it? That too in fewer lines? Maybe a built-in method? An efficient way can be preferred over fewer lines.
Thanks
The primary difference between PHP and Python is that PHP arrays are both associative and ordered, while in Python you can either have an ordered list
or an associative dict
, but not both in one data structure.*
* There's OrderedDict
and dict
is starting to become ordered itself, but let's stick with the primitives.
So fundamentally you'll need to think of different data structures. The typical way to do this is to have a list of tuples, with one tuple value representing your former index and the other value the former value:
[(0, 'foo'), (1, 'bar'), ...]
You can get to that from a normal list using enumerate
:
l = list(enumerate(my_list)) # ['foo', 'bar'] → [(0, 'foo'), (1, 'bar')]
And you can sort it in the process:
l = sorted(enumerate(my_list), key=lambda i: i[1]) # → [(1, 'bar'), (0, 'foo')]
Here lambda i: i[1]
simply sorts by the second tuple value, i.e. your former value. You can replace that with itemgetter(1)
from the operator
module for brevity, or adjust as necessary for your sorting condition.
If you want to turn that into an associative data structure again, use OrderedDict
:
from collections import OrderedDict
from operator import itemgetter
l = OrderedDict(sorted(enumerate(my_list), key=itemgetter(1)))