1

I have a list with 2 or 3 character strings with the last character being the same.

example_list = ['h1','ee1','hi1','ol1','b1','ol1','b1']

is there any way to sort this list using the order of another list.

order_list = ['ee','hi','h','b','ol']

So the answer should be something like example_list.sort(use_order_of=order_list)

Which should produce an output like ['ee1','hi1','h1','b1','b1','ol1','ol1']

I have found other questions on StackOverflow but I am still unable find a answer with a good explanation.

4
  • 3
    And what if an element is not in order_list, e.g. the first element in example_list: h1? Commented Sep 25, 2021 at 7:29
  • 2
    What is the desired output for your example? Commented Sep 25, 2021 at 7:31
  • Thanks for pointing that out. The order_list should in theory contain every single element in example_list. Commented Sep 25, 2021 at 7:31
  • desired output would be ['ee1','hi1','h1','b1','b1','ol1','ol1'] Commented Sep 25, 2021 at 7:33

3 Answers 3

2

You could build an order_map that maps the prefixes to their sorting key, and then use that map for the key when calling sorted:

example_list = ['h1','ee1','hi1','ol1','b1','ol1','b1']
order_list = ['ee','hi','h','b','ol']
order_map = {x: i for i, x in enumerate(order_list)}
sorted(example_list, key=lambda x: order_map[x[:-1]])

This has an advantage over calling order_list.index for each element, as fetching elements from the dictionary is fast.

You can also make it work with elements that are missing from the order_list by using dict.get with a default value. If the default value is small (e.g. -1) then the values that don't appear in order_list will be put at the front of the sorted list. If the default value is large (e.g. float('inf')) then the values that don't appear in order_list will be put at the back of the sorted list.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer. Can converting to a dict really make a difference in a short list. Because you would still have to go through the list for order_map = {x: i for i, x in enumerate(order_list)}
@DeeraWijesundara When you use order_list.index in your sorted key function, it gets called for every element, and it traverses order_list each time it is called, so the solution has a time complexity of O(n^2). Building the order_map dictionary takes one pass of order_list, and subsequent lookups in it in the sorted key function are each O(1), thereby making the solution have a time complexity of O(n). The difference between an O(n) and O(n^2) solution may not be significant for a small n, but given that the dictionary approach is hardly any more complicated it should be preferred
1

You can use sorted with key using until the last string of each element in example_list:

sorted(example_list, key=lambda x: order_list.index(x[:-1]))

Ourput:

['ee1', 'hi1', 'h1', 'b1', 'b1', 'ol1', 'ol1']

Note that this assumes all element in example_list without the last character is in order_list

4 Comments

.index has O(N) time complexity. Make this solution O(N^2). You could use some extra space mapping = mapping = dict(zip(order_list, range(len(order_list)))) then key = lambda x: mapping[x[:-1]].
@Ch3steR I'm aware of the complexity, but when the inputs are quite short, I think the simplicity comes before efficiency (purely my preference tho). In any case, @Will Da Silva's answer well demonstrates how to use dict for this purpose.
@Chris I never said you don't know. It was just a comment for future readers about the time complexity. Yes, when inputs are short it doesn't matter. My comment is for all the future readers who might use this solution without knowing the implications.
@Ch3steR Perhaps I should have mentioned about the simplicity vs efficiency in the first place :P But thank you for pointing out ;)
-1

Something like this? It has the advantage of handling duplicates.

sorted_list = [
    i
    for i, _
    in sorted(zip(example_list, order_list), key=lambda x: x[1])
]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.