Home > front end >  sort two nested lists according to value of one list in python
sort two nested lists according to value of one list in python

Time:05-14

I want to sort two nested lists according to value of one list.

predictions = np.array([[0, 1, 2, 3], [3, 2, 1, 0], [1, 2, 3, 0], [-1, -1, -1, -1]])
test_interaction_matrix = np.array([[1, 0, 0, 0], [0, 1, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]])

for i,(p,t) in enumerate(zip(predictions, test_interaction_matrix)):
    list1, list2 = (list(t) for t in zip(*sorted(zip(p, t))))
    print(list1, list2)

The sorting criterion depend on the test_interaction_matrix value, if it is one then bring the corresponding element in prediction in the front. The change of position should happen in both lists. For instance I want the first list in predictions to look like [0,3,2,1] with corresponding list in test_interaction_matrix like [1,0,0,0], for the next [2,0,3,1] and [1,1,0,0] and so on. Now printing the list I don't get the correct result with my code above. Thanks!

CodePudding user response:

You can use a list comprehension for fast approach:

predictions = np.array([[0, 1, 2, 3], [3, 2, 1, 0], [1, 2, 3, 0], [-1, -1, -1, -1]])
test_interaction_matrix = [[1, 0, 0, 0], [0, 1, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]])

pred = predictions.tolist()
order = test_interaction_matrix.tolist()

[list(zip(*sorted(zip(pred[i], order[i]), key=lambda pair: (pair[1], pair[0]), reverse=True)))[0] for i in range(len(pred))]

This code cycles over every position in the array (for i in range(len(pred))).

Step 1: For each position, it pairs up the elements in the arrays (zip(pred[i], order[i])):

[[(0,1), (1,0), (2,0), (3,0)], [(3,0), (2,1), (1,0), (0,1)], [...], ...]

Step 2: Sort the pairs inside the arrays (sorted(zip(...), key=lambda pair: (pair[1], pair[0]), reverse=True)):

The key parameters indicates how it will apply ordering: it will prioritize your test_interaction_matrix values, then the prediction values. Reverse is set to True so that you'll get descendent order.

[[(0,1), (3,0), (2,0), (1,0)], [(2,1), (0,1), (3,0), (1,0)], [...], ...]

Step 3: Will rebuild the original vectors test_interaction_matrix and predictions (list(zip(*sorted(...)))), in few words it's the inverse operation of Step 1:

[[(0, 3, 2, 1), (1, 0, 0, 0)], [(2, 0, 3, 1), (1, 1, 0, 0)], [...], ...]

Step 4: Get the first array (list(...)[0]), which corresponds to the predictions one, this time ordered:

[(0, 3, 2, 1), (2, 0, 3, 1), (3, 2, 1, 0), (-1, -1, -1, -1)]

CodePudding user response:

If I understand the question correctly, the following should work:

import numpy as np

predictions = np.array([[0, 1, 2, 3], 
                        [3, 2, 1, 0], 
                        [1, 2, 3, 0],
                        [-1, -1, -1, -1]])

test_interaction_matrix = np.array([[1, 0, 0, 0], 
                                    [0, 1, 0, 1], 
                                    [0, 0, 0, 0],
                                    [0, 0, 0, 0]])

r = predictions.shape[0]
sp = np.flip(predictions.argsort(axis=1), axis=1)
p = predictions[np.c_[:r], sp]
t = test_interaction_matrix[np.c_[:r], sp]
s = (-t).argsort(axis=1, kind="stable")
p = p[np.c_[:r], s]
t = t[np.c_[:r], s]

print(f"p:\n{p}\n\nt:\n{t}")

It gives:

p:
[[ 0  3  2  1]
 [ 2  0  3  1]
 [ 3  2  1  0]
 [-1 -1 -1 -1]]

t:
[[1 0 0 0]
 [1 1 0 0]
 [0 0 0 0]
 [0 0 0 0]]
  • Related