Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Advanced List sorting Python

I am trying to sort a dictionary which is in the form:

d = {'+A':234, '-B':212, 'A':454, '-C':991, '-A':124}

I want to sort it by key so that it is in the form:

+A, A, -A, +B, B, -B, etc

I have been trying to use sorted(d, key=lambda x: (x[1], x[0]) if len(x) == 2 else x[0]) but I cannot seem to find any way to sort the symbols correctly since they are not in the correct order on the ascii chart. What am I doing wrong?

like image 276
rmoro Avatar asked Dec 09 '22 11:12

rmoro


2 Answers

One simple way to do it

rank = ['+A', 'A', '-A', '+B', 'B', '-B', ...]
sorted(d.items(), key=lambda i: rank.index(i[0]))

If there are a lot of ranks, it'll be better to use a dict

rank = {'+A': 0, 'A': 1, '-A': 2, '+B': 3, 'B': 4, '-B': 5, ...}
sorted(d.items(), key=lambda i: rank[i[0]])

You can use a lambda function like this. Note that it's important to use the backward slice to make sure the letters are sorted before their modifiers.

sorted(d.items(), key=lambda i:(','+i[0])[::-1])

But I think the explicit rank is clearer and not prone to bugs like the one in @Hari's answer. (5 people voted for it without noticing the bug so far)

If you really do just need the keys sorted (why?), you can simply use rank.get instead of a lambda function:

>>> rank = {'+A': 0, 'A': 1, '-A': 2, '+B': 3, 'B': 4, '-B': 5, '+C': 6, 'C': 7, '-C': 8}
>>> d = {'+A':234, '-B':212, 'A':454, '-C':991, '-A':124}
>>> sorted(d, key=rank.get)
['+A', 'A', '-A', '-B', '-C']

but it's probably better to skip sorted altogether

>>> rank = ['+A', 'A', '-A', '+B', 'B', '-B', '+C', 'C', '-C']
>>> d = {'+A':234, '-B':212, 'A':454, '-C':991, '-A':124}
>>> [k for k in rank if k in d]
['+A', 'A', '-A', '-B', '-C']

If you hate typing all those '

>>> rank = '+A A -A +B B -B +C C -C'.split()
like image 175
John La Rooy Avatar answered Dec 11 '22 10:12

John La Rooy


This should work:

sorted(d, key=lambda x: (x[1], x[0]) if len(x) == 2 else (x[0], ','))

The ascii value for , lies between + and -, so you can put a dummy , at the end for comparison.

>>> d = {'+A':234, '-B':212, 'A':454, '-C':991, '-A':124, '+B':1, 'B':98, '+C':232, 'C':23}
>>> sorted(d, key=lambda x: (x[1], x[0]) if len(x) == 2 else (x[0], ','))
['+A', 'A', '-A', '+B', 'B', '-B', '+C', 'C', '-C']

You can also simply reverse the key and append a , for the comparator:

sorted(d, key=lambda x: x[::-1] + ',')

So +A, A, -A are compared as A+,, A and A-,.

like image 26
Hari Menon Avatar answered Dec 11 '22 09:12

Hari Menon