Victor Sankar Ghosh Victor Sankar Ghosh -4 years ago 189
Python Question

How to do multiple comparisons while sorting a dictionary of lists in python?

I have a dictionary of lists,

summary
:

summary = {
'Raonic': [2, 0, 11, 122, 16, 139],
'Halep': [2, 2, 10, 75, 6, 60],
'Kerber': [2, 0, 7, 68, 7, 71],
'Wawrinka': [1, 2, 14, 133, 13, 128],
'Djokovic': [2, 2, 10, 75, 8, 125],
}


I wish to print out to the screen (standard output) a summary in decreasing order of ranking, where the ranking is according to the criteria 1-6 in that order (compare item 1 (of the list), and if equal compare item 2 (of the list), if those are equal compare item 3 (of the list). This comparison continues till item 4 of the list in descending order.

However the comparison of item 5 and item 6 of the lists must be done in the ascending order.

Output:

Halep 2 2 10 75 6 60
Djokovic 2 2 10 75 8 125
Raonic 2 0 11 122 16 139
Kerber 2 0 7 68 7 71
Wawrinka 1 2 14 133 13 128


My Solution was:

for key, value in sorted(summary.items(), key=lambda e: e[1][0], reverse = True):
print(key, end=' ')
for v in value:
print(v, end=' ')
print()


However my solution merely succeeds at sorting on column 1 of the list.

Visit this site for full question

Answer Source

For numeric values, you can negate the value to get the inverse sort. For your sort key, return a sequence of the values that are to be sorted, negating the values that go in the 'opposite' direction:

ranked = sorted(
    summary.items(),
    key=lambda kv: kv[1][:4] + [-kv[1][4], -kv[1][5]],
    reverse=True)

This produces (key, value) tuples in sorted order, as dictionaries are unordered.

For ('Halep', [2, 2, 10, 75, 6, 60]), the sort key lambda returns [2, 2, 10, 75, -6, -60], ensuring that this is sorted before 'Djokovic' where the sort key is set to [2, 2, 10, 75, -8, -125], because in reversed sort order (reverse=True), -6 is sorted before -8. However, any difference in value in the first 4 columns is sorted in the other direction, so anything with 3 or more in the first column will be sorted before ('Halep', [...]), or anything starting with 2, 3 or higher, etc.

Where values are not numeric and there is no other 'inverse' value option available for the columns, you'd have to sort twice. First on the last 2 columns (sorting in ascending order), then on the first 4 columns (in descending, so reversed, order):

# non-numeric option
part_sorted = sorted(summary.items(), key=lambda kv: kv[1][-2:])
ranked = sorted(part_sorted, key=lambda kv: kv[1][:4], reverse=True)

This works because Python's sort algorithm (called Timsort) is stable, the relative order of any two inputs for which the sort key is exactly equal is untouched. So any keys A and B, where only the last on or two columns differ, are given an relative ordering in part_sorted that then doesn't change in ranked because the part_sorted order is untouched. If A is sorted after B in the first sort then the second sort will leave A after B.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download