简体   繁体   中英

Python: sorting a list according to the resulting order on its copy

Related problem : in the final part I'm looking for a quicker method than a nested for loop.

Say we have a list a = [a_0, a_1, ..., a_n] . We create a deep copy of a called b = [b_0, b_1, ..., b_n] , in which b_i and a_i are identical objects but stored separately. Now we perform a certain sorting algorithm some_sort on b to get an ordering order_b = [b'_0, b'_1, ..., b'_n] in which those b'_i are the same objects objects in b permuted (since the some_sort algorithm is destructive, elements in order_b are no longer identical to those in b , but the references are maintained). Now, I want a to be sorted according to the same ordering in order_b , ie, get an ordering order_a = [a'_0, a'_1, ..., a'_n] which is a permutation from a in the same way as order_b is permuted from b , but I can't perform the sorting algorithm some_sort on a because that algorithm is destructive. Is there any quick way to do this?

Example: a = [a_0, a_1, a_2, a_3] , deep copy of a is b = [b_0, b_1, b_2, b_3] . The resulting ordering on b is order_b = [b_3, b_2, b_0, b_1] , then what I want is to obtain order_a = [a_3, a_2, a_0, a_1] according to order_b .

import copy   
a = [2,4,3,1]
Out[94]: [2, 4, 3, 1]
#create a deep copy of a
b = copy.deepcopy(a)
Out[96]: [2, 4, 3, 1]
#add index of b and its value to a tuple
b1 = [(v,k) for k, v in enumerate(b)]
Out[98]: [(2, 0), (4, 1), (3, 2), (1, 3)]
#sort b1 (can using whatever criteria for sorting)
b1 = sorted(b1)
Out[100]: [(1, 3), (2, 0), (3, 2), (4, 1)]
#extract elements from a using the order of b1.
[a[e] for e in [e[-1] for e in b1]]
Out[101]: [1, 2, 3, 4]

You mentioned you keep the original b_i reference in b'_i , so you can create a reverse lookup of {b_i: idx} , eg (pseudo):

mapping = {b'_i->b_i: idx for idx, b'_i in enumerate(order_b)}
[m for m, n in sorted(zip(a,b), key=lambda x: mapping[x[1]])]

Demo, take a list of numbers and letters, randomize the letters and return the numbers in the same order as the randomize letters:

In [1]:
import random
a = list(range(10))
b = list('abcdefghij')
b_ = random.sample(b, k=len(b))
''.join(b_)

Out[1]:
'idfehbgacj'

In [2]:
mapping = {k: idx for idx, k in enumerate(b_)}
[m for m, n in sorted(zip(a,b), key=lambda x: mapping[x[1]])]

Out[2]:
[8, 3, 5, 4, 7, 1, 6, 0, 2, 9]

i have simple solution for this:

a_ = [ a[i] for i in (b.index(j) for j in b_) ]

        _or_  

b_perm = [ b.index(j) for j in b_ ]
a_ = [ a[i] for i in b_perm ]

import random
a = list(range(10))
b = list('abcdefghij')
b_ = random.sample(b, k=len(b))

b_ = ['c', 'b', 'f', 'i', 'e', 'a', 'h', 'g', 'j', 'd']

a_ = [a[i] for i in (b.index(j) for j in b_)]

a_ = [2, 1, 5, 8, 4, 0, 7, 6, 9, 3]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM