4

Below is the use-case I am trying to solve:

I have 2 lists of lists: (l and d)

In [1197]: l
Out[1197]: 
[['Cancer A', 'Ecog 9', 'Fill 6'],
 ['Cancer B', 'Ecog 1', 'Fill 1'],
 ['Cancer A', 'Ecog 0', 'Fill 0']]

In [1198]: d
Out[1198]: [[100], [200], [500]]

It's a 2-part problem here:

  1. Sort l based on the priority of values. eg: Cancer, Ecog and Fill (in this case key=(0,1,2)). It could be anything like Ecog, Cancer, Fill so, key=(1,0,2).
  2. Sort d in the same order in which l has been sorted int above step.

Step #1 I'm able to achieve, like below:

In [1199]: import operator
In [1200]: sorted_l = sorted(l, key=operator.itemgetter(0,1,2))

In [1201]: sorted_l
Out[1200]: 
[['Cancer A', 'Ecog 0', 'Fill 0'],
 ['Cancer A', 'Ecog 9', 'Fill 6'],
 ['Cancer B', 'Ecog 1', 'Fill 1']]

Now, I want to sort values of d in the same order as the sorted_l.

Expected output:

In [1201]: d
Out[1201]: [[500], [100], [200]]

What is the best way to do this?

Mayank Porwal
  • 33,470
  • 8
  • 37
  • 58
  • 2
    No, this is not a duplicate of the question marked. Please read the question properly. – Mayank Porwal Oct 01 '20 at 06:37
  • Basically, you just zip the lists together. Sort that, but take it into account in your key function, so if you do `sorted(zip(l, d), key=lambda pair: (pair[0][0], pair[0][1], pair[0][2]))`. Although note, as I mentioned above, your key function was doing anything useful, so in this particular case, you just do `sorted(zip(l, d), key=itemgetter(1))` – juanpa.arrivillaga Oct 01 '20 at 06:37
  • I did read the question properly, I think. Here's what you want: `l_sorted, d_sorted = map(list, zip(*sorted(zip(l, d), key=lambda x: x[0])))`. What am I missing? – juanpa.arrivillaga Oct 01 '20 at 06:37
  • @juanpa.arrivillaga I want the list `l` to be sorted in any order I want. Priority could be `Ecog, Cancer, Fill`. So I want to have the flexibility to sort the first list by providing `itemgetter`. That is not pointless. Now, `d` should be sorted in the same order `l` is sorted. Hope I am clear with this. I somehow wanted to combine both sortings, hence I said it's not a duplicate. – Mayank Porwal Oct 01 '20 at 07:20
  • *That's exactly what the linked duplicates describe*. And the solution I provided works, but more generally, `key = itemgetter(whatever)` then just `sorted_l, sorted_d = map(list, zip(*sorted(zip(l, d), key=lambda x: key(x[0]))))` – juanpa.arrivillaga Oct 01 '20 at 07:25
  • Your solution would not work if I wanted to sort `l` like this: `[['Ecog 0 ', Cancer A', 'Fill 0'], ['Ecog 9', 'Cancer A', 'Fill 6'], ['Ecog 1', Cancer B', 'Fill 1']]`. – Mayank Porwal Oct 01 '20 at 07:41
  • I want it to be flexible. It could be any priority. In my question I just took an example. – Mayank Porwal Oct 01 '20 at 07:44
  • You have to understand, I want 2 different sortings here. One for sorting `l` in any order and another to sort `d` in the same order `l` has been sorted. Pease get this clarified before marking this a duplicate. I did my research before posting. – Mayank Porwal Oct 01 '20 at 07:46
  • **That is exactly what the linked duplicates tell you how to do**. That is what I've told you how to do repeatedly. But here, how would you sort `l` in your second example? – juanpa.arrivillaga Oct 01 '20 at 07:46
  • What is a `linked duplicate`? Please point me to the exact command. And what do you mean by `would you sort l in your second example.` If my question seems confusing to you, I can re-phrase it right now. But I need help urgently. – Mayank Porwal Oct 01 '20 at 07:50
  • There are *two* linked duplicates at the top of your question in the message that explains why it was closed, they *both* show you how to sort a list based on how you sorted the first one, as I've shown you *repeatedly*, it is `first, second = zip(*sorted(zip(first, second), lambda x: key(x[0]))` where `key` represents whatever function would sort your first list, e.g. `key = itemgetter(2, 0, 1)`. – juanpa.arrivillaga Oct 01 '20 at 07:52
  • Ok, this makes sense. I did this : `a , b = map(list, zip(*sorted(zip(l, d), key=operator.itemgetter(2, 0, 1))))` and it's failing saying `IndexError: tuple index out of range`. – Mayank Porwal Oct 01 '20 at 07:56
  • You have to compose the key functions. First you extract the first element, and then you apply the key function that you would apply to sort the first list (since the first element of the tuple will be the element from the first list). So, `key = itemgetter(2, 0, 1); sorted(zip(l, d), key=lambda x: key(x[0]))` – juanpa.arrivillaga Oct 01 '20 at 07:57
  • Yes, this works. Thanks for that. I still feel if you would have put this as an answer, it would have solved a lot of queries. If you can do that would be great. I have also re-phrased my question. – Mayank Porwal Oct 01 '20 at 08:07
  • Here, i'll re-open – juanpa.arrivillaga Oct 01 '20 at 08:10

1 Answers1

0

Below is the solution with help from @juanpa.arrivillaga :

In [1272]: import operator
In [1273]: key = operator.itemgetter(0, 1, 2)

# Here param key, lets you sort `l` with your own function.
In [1275]: sorted_l,sorted_d = zip(*sorted(zip(l, d), key=lambda x: key(x[0])))

In [1276]: sorted_l
Out[1276]: 
(['Cancer A', 'Ecog 0', 'Fill 0'],
 ['Cancer A', 'Ecog 9', 'Fill 6'],
 ['Cancer B', 'Ecog 1', 'Fill 1'])

In [1277]: sorted_d
Out[1277]: ([500], [100], [200])
Mayank Porwal
  • 33,470
  • 8
  • 37
  • 58