Skip to content Skip to sidebar Skip to footer

Python: How Do I Sort Array X But Carry The Same Relative Sort Over To Y?

For example X=[5,6,2,3,1] Y=[7,2,3,4,6] I sort X: X=[1,2,3,5,6] But I want the same relative sort applied to Y so the numbers stay in the same positions relative to each other as

Solution 1:

Usually, you do a zip-sort-unzip for this

>>>X = [5,6,2,3,1]>>>Y = [7,2,3,4,6]

Now sort them together:

>>>sorted(zip(X,Y))
[(1, 6), (2, 3), (3, 4), (5, 7), (6, 2)]

Pair that with a "unzip" (zip(*...))

>>>zip(*sorted(zip(X,Y)))
[(1, 2, 3, 5, 6), (6, 3, 4, 7, 2)]

which you could unpack:

>>>X,Y = zip(*sorted(zip(X,Y)))>>>X
(1, 2, 3, 5, 6)
>>>Y
(6, 3, 4, 7, 2)

Now you have tuple instead of list objects, but if you really need to, you can convert it back.


As pointed out in the comments, this does introduce a very slight dependence on the second list in the sort: Consider the lists:

X = [1,1,5,7] #sorted alreadyY = [2,1,4,6] #Not already sorted.

With my "recipe" above, at the end of the day, you'll get:

X = (1,1,5,7)
Y = (1,2,4,6) 

which might be unexpected. To fix that, you could pass a key argument to sorted:

from operator import itemgetter
X,Y = zip(*sorted(zip(X,Y),key=itemgetter(0)))

Demo:

>>>X
[1, 1, 5, 7]
>>>Y
[2, 1, 4, 6]
>>>XX,YY = zip(*sorted(zip(X,Y)))>>>XX
(1, 1, 5, 7)
>>>YY
(1, 2, 4, 6)
>>>from operator import itemgetter>>>XX,YY = zip(*sorted(zip(X,Y),key=itemgetter(0)))>>>XX
(1, 1, 5, 7)
>>>YY
(2, 1, 4, 6)

Solution 2:

Another idea:

>>>d = dict(zip(Y, X))>>>sorted(Y, key=d.get)
[6, 3, 4, 7, 2]

You just use corresponding values in X as keys while sorting Y.

Solution 3:

Here is a way to preserve order even if there are duplicate items:

defargsort(seq):
    '''
    >>> seq = [1,3,0,4,2]
    >>> index = argsort(seq)
    [2, 0, 4, 1, 3]

    Given seq and the index, you can construct the sorted seq:
    >>> sorted_seq = [seq[x] for x in index]
    >>> assert sorted_seq == sorted(seq)

    Given the sorted seq and the index, you can reconstruct seq:
    >>> assert [sorted_seq[x] for x in argsort(index)] == seq
    '''returnsorted(range(len(seq)), key=seq.__getitem__)

X = (1,1,5,7)
Y = (1,2,4,6)
index = argsort(X)
print([Y[i] for i in index])

yields

[1, 2, 4, 6]

Regarding speed, using_argsort appears to be faster than using_zip or using_dict:

def using_argsort():
    index = argsort(X)
    return [X[i] for i in index], [Y[i] for i in index]

def using_zip():
    returnzip(*sorted(zip(X,Y), key = operator.itemgetter(0)))

def using_dict():
    d = dict(zip(Y,X))
    return sorted(X), sorted(Y, key = d.get)

X = [5,6,2,3,1]*1000
Y = [7,2,3,4,6]*1000

In [18]: %timeit using_argsort()
1000 loops, best of 3: 1.55 ms per loop

In [19]: %timeit using_zip()
1000 loops, best of 3: 1.65 ms per loop

In [21]: %timeit using_dict()
100 loops, best of 3: 2 ms per loop

Solution 4:

I'm assuming x and y have the same number of elements. when sorting x, everytime you swap two value, say, x.swap(i,j), you do y.swap(i,j) as well. By the way, I don't know python so this is not python syntax.

Post a Comment for "Python: How Do I Sort Array X But Carry The Same Relative Sort Over To Y?"