0

I'm having a set of lists where I need to sort the list in a specific order.

List:

colour_1 = ['orange','purple','yellow','black','brown','pink','blue','green']
colour_2 = ['white','violet','blue','red','yellow','purple']
colour_3 = ['Gray','silver','green','yellow','gold']

The order which i need to sort:

custom_order = ['blue','yellow','green','purple',#remaining_colours]

Expected output:

colour_1 =  ['blue','yellow','green','purple','orange','black','brown','pink']
colour_2 = ['blue','yellow','purple','white','violet','red']
colour_3 = ['yellow','green','gray','silver','gold']

What I need:

1)Check if values in custom_order are present in colour_lists.

2)If present in colour_list, arrange them in the specified order. If the values not present skip the value and search for the next value. (If "yellow" is not present in colour_list skip "yellow" and search if "green" is present in colour_list)

3)Once the custom_order is inserted, append the remaining values to the list.

How to sort the list in the custom order in python?

Thanks in advance.

Thra
  • 87
  • 2
  • 11
  • Does this answer your question? [Sorting list with custom order in Python](https://stackoverflow.com/questions/59237473/sorting-list-with-custom-order-in-python) – Mykola Zotko Oct 28 '20 at 16:30
  • Or alternatively [Sorting list based on values from another list](https://stackoverflow.com/questions/6618515/sorting-list-based-on-values-from-another-list) – Stef Oct 29 '20 at 14:36

2 Answers2

1

You can use the optional keyword argument key to list.sort or sorted to implement a custom sort. See the documentation.

Here the key might be custom_order.index, which returns the position of an item in custom_order.

However, note that calling .index() repeatedly results in a time complexity of O(n * m), where n is the length of the list to be sorted and m the length of custom_order, because .index() needs to iterate through the list everytime.

Instead of calling .index repeatedly, you can use a python dict to store the indices:

custom_order = {c:i for i,c in enumerate(['blue','yellow','green','purple'])}

def customSort(l):
  l.sort(key=lambda c:custom_order.get(c, len(custom_order)))

def customSorted(l):
  return sorted(l, key=lambda c:custom_order.get(c, len(custom_order)))

print(customSorted(['orange','purple','yellow','black','brown','pink','blue','green']))
# ['blue', 'yellow', 'green', 'purple', 'orange', 'black', 'brown', 'pink']

Note how the second argument of dict.get is the default value to use in case the colour is not found in the dict.

This will place green, yellow, green, purple first, and conserve the relative order of the other colours. If you want, you can sort the other colours according to some other criterion, by using a tuple (index, othercriterion) as the key instead of just index.

For instance, to sort remaining colours alphabetically:

custom_order = {c:(i,c) for i,c in enumerate(['blue','yellow','green','purple'])}

def customSort(l):
  l.sort(key=lambda c:custom_order.get(c, (len(custom_order),c)))

def customSorted(l):
  return sorted(l, key=lambda c:custom_order.get(c, (len(custom_order),c)))

print(customSorted(['orange','purple','yellow','black','brown','pink','blue','green']))
# ['blue', 'yellow', 'green', 'purple', 'black', 'brown', 'orange', 'pink']

Note how I replaced c:i with c:(i,c) in the dict, and len(custom_order) with (len(custom_order),c) in the default value, to use the colour name as a tie-breaker.

Stef
  • 13,242
  • 2
  • 17
  • 28
0

My approach: Create a custom sorting function and pass it to the built-in sort() method. The built-in sort() method can sort any list. The way it works is that for every element in the list, the sort() method will call the key() function (which you provide it with). The key() function will compute the key/rank for every item, and then use that rank/key to actually sort the items in the list.

So, to recap, they key function accepts an item from the list as an argument and should return that item's rank. The solution is simple. If the color which you pass as an argument is in your "custom_order" then the key() function should return the index of that color. The lower the index, the lower the key, which ensures that for example "blue" will be the color with the lowest key. Since you don't care about other colors, you can simply assign them a key of "len(custom_order)". This makes sure that all colors which you don't care about will have a higher key-value than any colors which you do care about.

I think the code will be easier to understand than my solution:

def my_custom_sort(color):
custom_order = ['blue', 'yellow', 'green', 'purple']
if color in custom_order:
    return custom_order.index(color)
else:
    return len(custom_order)


colour_1 = ['orange','purple','yellow','black','brown','pink','blue','green']
colour_2 = ['white','violet','blue','red','yellow','purple']
colour_3 = ['Gray','silver','green','yellow','gold']

colour_1.sort(key=my_custom_sort)
colour_2.sort(key=my_custom_sort)
colour_3.sort(key=my_custom_sort)

print(colour_1)
print(colour_2)
print(colour_3)

The output of this code is as the OP has requested:

['blue', 'yellow', 'green', 'purple', 'orange', 'black', 'brown', 'pink']
['blue', 'yellow', 'purple', 'white', 'violet', 'red']
['yellow', 'green', 'Gray', 'silver', 'gold']

Useful links:

.index() method: https://www.programiz.com/python-programming/methods/list/index

.sort() method: https://wiki.python.org/moin/HowTo/Sorting/

waykiki
  • 914
  • 2
  • 9
  • 19