Robert
Robert

Reputation: 151

Sort 2 list linked to each other

I go stuck on a problem and I cannot think of any efficient way to do this. The problem is the following:

I got 2 lists, each with n up to 10^3.

v = [v_1, v_2, ..., v_n]
w = [w_1, w_2, ..., w_n]

In the following example n = 3.

v = [60, 100 , 120] 
w = [20, 50, 30]

I need to sort both lists based on the decreasing order of the following equation: v_i/w_i

So in this case I would get:

v_1/w_1 = 3
v_2/w_2 = 2
v_3/w_3 = 4

After that I need to sort both lists (depended to each other) by the decreasing order and I would get the following result.

v_new = [120, 60, 100]
w_new = [30, 20, 50]

I know there is a way with sorted(zip(X,Y), but doing so it would change my list in a tuple and I need it as a list. Any suggestions?

Upvotes: 5

Views: 128

Answers (4)

Bi Rico
Bi Rico

Reputation: 25813

The question doesn't mention numpy, but I thought I'd add an answer using numpy because it handles this kind of thing really well. Numpy has an argsort that can be used to apply the ordering of any sort to other arrays, for example:

import numpy as np

v = np.array([60, 100 , 120])
w = np.array([20, 50, 30])

order = np.argsort(v / w)[::-1]
v_new = v[order]
w_new = w[order]

argsort doesn't have a reverse argument, but we can always just invert the output using [::-1].

Upvotes: 0

Austin
Austin

Reputation: 26039

Sort based on condition using the key of sorted which then gives a list of tuples and we use zip to separate them to two lists:

v = [60, 100 , 120] 
w = [20, 50, 30]

v, w = map(list, zip(*sorted(zip(v, w), key=lambda x: - x[0] / x[1])))

print(v)  # [120, 60, 100]
print(w)  # [30, 20, 50]

Alternatively, you could use reverse=True in the same code like:

v = [60, 100 , 120] 
w = [20, 50, 30]

v, w = map(list, zip(*sorted(zip(v, w), key=lambda x: x[0] / x[1], reverse=True)))

which also yields what is desired.

Upvotes: 3

atline
atline

Reputation: 31574

You can use pandas:

import pandas as pd
v = [60, 100, 120]
w = [20, 50, 30]
vv = pd.Series(v)
ww = pd.Series(w)
new_index = list((vv/ww).sort_values(ascending=False).index.values)
v_new = list(vv.reindex(new_index))
w_new = list(ww.reindex(new_index))
print(v_new)
print(w_new)

Output:

[120, 60, 100]

[30, 20, 50]

Upvotes: 0

Bi Rico
Bi Rico

Reputation: 25813

Python's sort functions can take a key, you can use a lambda function to define the key you want to sort over. In this case, i'd suggest sorting the indices and then applying the order to both v and w. For example:

v = [60, 100 , 120] 
w = [20, 50, 30]
order = sorted(range(len(v)), key=lambda i: v[i] / w[i], reverse=True)

v_new = [v[i] for i in order]
w_new = [w[i] for i in order]

Upvotes: 5

Related Questions