1

I know how to sort one list to match the order of another list. I also know how to sort one list on two keys (using a lamdba function like key = lambda i: (i[0], i[1])). But I need to sort one list to match the order of another list, where that second list has two sort keys. For example:

order_list = [['a', 2], ['c', 3], ['b', 1], ['e', 4]]
listB = [['c', 3, 'red', 'car'], ['e', 4, 'green', 'bus'], ['b', 1, 'blue', 'bike'], ['a', 2, 'yellow', 'plane']]

Desired output:

sorted_listB = [['a', 2, 'yellow', 'plane'], ['c', 3, 'red', 'car'], ['b', 1, 'blue', 'bike'],['e', 4, 'green', 'bus']]

I tried by writing this - even though it's bad form I just wanted to see if it would work and it does not:

def sort_key(x):
    """ Find the matching element in reference sorted list
    """
    # bad form, referencing non-local var
    for a in order_list:
        if a[0] == x[0] and a[1] == x[1]:
            return a

    sorted_listB = sorted(listB, key = sort_key)

Any clever thoughts on how to do this? Preferably without turning the nested list into a single key. I know I can do that...was trying to stretch my skills and do it this way, but I'm stuck.

Pranav Hosangadi
  • 23,755
  • 7
  • 44
  • 70
Jess
  • 186
  • 3
  • 13
  • 1
    Please see [formatting help](/help/formatting). Indenting only the first line of your code may make it _appear_ to have been formatted correctly, but it messes up the indentation relative to the rest of your code. Please either indent _all_ of your code (using the code block button in the editor) or surround the entire code block in code fences (three backticks (`\``) on the lines before and after the code – Pranav Hosangadi Jan 02 '23 at 17:50
  • This problem seems identical to sorting by order of another list. Only in this case the elements in the other list are lists themselves, and you get the corresponding element from the list to be sorted by slicing the items being sorted. – Pranav Hosangadi Jan 02 '23 at 17:56
  • 1
    "I tried by writing this" - was it a typo putting `sorted_listB = sorted(listB, key = sort_key)` inside the `sort_key` definition? (It still doesn't work, but I want to make sure if you caught that. And the underlying reasoning is pretty close, although it doesn't do quite enough while also being more complicated than necessary.) – Karl Knechtel Jan 02 '23 at 19:25

1 Answers1

2

One approach:

order_list = [['a', 2], ['c', 3], ['b', 1], ['e', 4]]
listB = [['c', 3, 'red', 'car'], ['e', 4, 'green', 'bus'], ['b', 1, 'blue', 'bike'], ['a', 2, 'yellow', 'plane']]

# use a dictionary to map the values to the priorities
keys = {tuple(e): i for i, e in enumerate(order_list)}

# then use the first to elements of each sub-list to check for the priority
sorted_listB = sorted(listB, key=lambda x: keys.get(tuple(x[:2])))
print(sorted_listB)
print(sorted_listB)

Output

[['a', 2, 'yellow', 'plane'], ['c', 3, 'red', 'car'], ['b', 1, 'blue', 'bike'], ['e', 4, 'green', 'bus']]

Or, if you wish, fix your function to return index values using enumerate as below:

def sort_key(x):
    """ Find the matching element in reference sorted list
    """
    # bad form, referencing non-local var
    for i, a in enumerate(order_list):
        if a[0] == x[0] and a[1] == x[1]:
            return i
Dani Mesejo
  • 61,499
  • 6
  • 49
  • 76
  • 1
    Thanks! I like the first one...I was bothered by the bad form of my function. But thank you for fixing my sort_key() function - now I understand why it wasn't working. I appreciate that. – Jess Jan 02 '23 at 18:48