Custom Python List Sorting

Custom Python list sorting

It's documented here.

The sort() method takes optional arguments for controlling the
comparisons.

cmp specifies a custom comparison function of two arguments (list
items) which should return a negative, zero or positive number
depending on whether the first argument is considered smaller than,
equal to, or larger than the second argument: cmp=lambda x,y:
cmp(x.lower(), y.lower()). The default value is None.

Custom sort order in Python

There's no need to use a lambda in the sorted function. Just supply it the index function of list1:

sorted(list2, key=list1.index)

Sort a list of lists with a custom compare function

>>> l = [list(range(i, i+4)) for i in range(10,1,-1)]
>>> l
[[10, 11, 12, 13], [9, 10, 11, 12], [8, 9, 10, 11], [7, 8, 9, 10], [6, 7, 8, 9], [5, 6, 7, 8], [4, 5, 6, 7], [3, 4, 5, 6], [2, 3, 4, 5]]
>>> sorted(l, key=sum)
[[2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9, 10], [8, 9, 10, 11], [9, 10, 11, 12], [10, 11, 12, 13]]

The above works. Are you doing something different?

Notice that your key function is just sum; there's no need to write it explicitly.

How to custom sort a list in python

First of all, make your keyorder a dict because list.index is an O(n) operation you don't want to perform for every comparison the sorting algorithm does.

>>> keyorder = 'ID', 'GE','FN','LN','MN','EM', 'ST'
>>> keyorder = dict(zip(keyorder, range(len(keyorder))))
>>>
>>> keyorder
{'FN': 2, 'GE': 1, 'ID': 0, 'LN': 3, 'ST': 6, 'EM': 5, 'MN': 4}

Now you can sort by splitting the part before the : from each of your strings and get the corresponding priority from keyorder.

>>> data = ['ID:123 GE:m FN:Amir LN:Maleki EM:a@b.c MN:0400101010  ST:VIC']
>>> data = data[0].split()
>>> sorted(data, key=lambda x: keyorder[x.split(':', 1)[0]])
['ID:123', 'GE:m', 'FN:Amir', 'LN:Maleki', 'MN:0400101010', 'EM:a@b.c', 'ST:VIC']

(The first two lines here sanitize your Data list because it's just a list of one element containing a string.)

Python: How to custom order a list?

You could use a dictionary that would map every first element to its "weight" and then check this dictionary inside a sorting function.

Something like:

d = { "Report": 1,
"Article": 2,
"Book": 3 }
result = sorted(mylist, key=lambda x:d[x[0]])

How to custom sort in a Python list?

Your code fails with an AttributeError because you are trying to do a lookup of id in a dict object, which doesn't have one. You need to access the desired dictionary key:

sorted(demo, key=lambda x: x['id'])

However, that will fail with a KeyError if at least one entry in the list does not have the id key. In that case, you can use:

sorted(demo, key=lambda x: x.get("id"))

Optionally you can use a default value in the get, if you wish to put all the entries with no id above or below the rest. In this case, the following would send entries with no id to the bottom:

sorted(demo, key=lambda x: x.get("id", "99"))


It may also happen that you have an id like 12#10 and you don't want it to be between 12#1 and 12#2. To solve that problem, you need to split the id and have a more complex sorting function.

def get_values(item):
return [int(x) for x in item['id'].split('#')]

def compare(a, b):
a = get_values(a)
b = get_values(b)
if not a[0] == b[0]:
return a[0] - b[0]
return a[1] - b[1]

Then you call sorted using that comparison function:

sorted(demo, cmp=compare)

Or in Python 3, where cmp has been eliminated:

from functools import cmp_to_key
sorted(demo, key=cmp_to_key(compare))

Custom sort order of list

Demonstration:

>>> mylist1 = ['alpha', 'green']
>>> mylist2 = ['blue', 'alpha', 'red']
>>> sort_order = ['red', 'blue', 'green', 'alpha']
>>> mylist1.sort(key=sort_order.index)
>>> mylist1
['green', 'alpha']
>>> mylist2.sort(key=sort_order.index)
>>> mylist2
['red', 'blue', 'alpha']

Explanation:

The key parameter in list.sort causes the list to determine the order by comparing key(element) instead of element. For example, to do case-insensitive sort, you can pass a key function which makes the string lowercase. The lowercase elements are compared, but the original elements are preserved:

>>> x = ["age", "Bonkers", "cheese"]
>>> x.sort()
>>> x
['Bonkers', 'age', 'cheese']
>>> str.lower("Bonkers")
'bonkers'
>>> x.sort(key=str.lower)
>>> x
['age', 'Bonkers', 'cheese']

Using sort_order.index for the key uses the index that element has in the sort_order list to determine the order instead of the element itself. So 'red' uses 0, 'blue' uses 1, etc... the result is that the list to be sorted gets sorted according to where each element is in sort_order.

Sort a list with a custom order in Python

SORT_ORDER = {"DINT": 0, "INT": 1, "BOOL": 2}

mylist.sort(key=lambda val: SORT_ORDER[val[1]])

All we are doing here is providing a new element to sort on by returning an integer for each element in the list rather than the whole list. We could use inline ternary expressions, but that would get a bit unwieldy.

Sorting list with custom order in Python

You must sort according to the first letter of the words:

list1 = ['Alpha', 'Beta', 'Charlie', 'Delta', 'Echo'] 

list2 = ['B', 'A', 'E', 'C', 'D']

out = list(sorted(list1, key=lambda word: list2.index(word[0])))
print(out)
# ['Beta', 'Alpha', 'Echo', 'Charlie', 'Delta']

index will have to iterate on list2 each time though. It might be more efficient to build a dict giving the index of each letter first, so that we can find the indices in O(1) when sorting:

list1 = ['Alpha', 'Beta', 'Charlie', 'Delta', 'Echo'] 

list2 = ['B', 'A', 'E', 'C', 'D']
dict2 = {letter: index for index, letter in enumerate(list2)}

out = list(sorted(list1, key=lambda word: dict2[word[0]]))
print(out)
# ['Beta', 'Alpha', 'Echo', 'Charlie', 'Delta']


Related Topics



Leave a reply



Submit