Reputation: 151
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
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
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
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
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