Reputation: 151
Halo, want to sort lists of dicts by value:
a = [{'cavity' : '11A', 'ltg_nr' : 'Ltgnr11A'},
{'cavity' : '20', 'ltg_nr' : 'Ltgnr20'},
{'cavity' : '10', 'ltg_nr' : 'Ltgnr10'},
{'cavity' : '17B', 'ltg_nr' : 'Ltgnr17B'},
{'cavity' : '1K', 'ltg_nr' : 'Ltgnr1K'},
{'cavity' : '11A', 'ltg_nr' : 'Ltgnr11A'},
{'cavity' : '11A', 'ltg_nr' : 'Ltgnr11A'},
{'cavity' : '22', 'ltg_nr' : 'Ltgnr22'},
{'cavity' : '21A', 'ltg_nr' : 'Ltgnr21A'},
{'cavity' : '21C', 'ltg_nr' : 'Ltgnr21C'},
{'cavity' : '21B', 'ltg_nr' : 'Ltgnr170'},
{'cavity' : '101', 'ltg_nr' : 'Ltgnr170'},
{'cavity' : '22AA', 'ltg_nr' : 'Ltgnr170'},
{'cavity' : '100A', 'ltg_nr' : 'Ltgnr170'}]
newList= sorted(a, key=lambda k: (len(k['cavity']),k['cavity']) )
print "-"*20 + ' sorted ' + "-"*20
for k in newList:
print k['cavity']
and the result is not what I excepted:
C:\Python27>python.exe test_dict.py
-------------------- sorted --------------------
10
1K
20
22
101
11A
11A
11A
17B
21A
21B
21C
100A
22AA
I will first sort by numeric and then by alpha characters. How can I do that :
1K
10
11A
11A
11A
17B
20
21A
21B
21C
22
22AA
100A
101
All sugestions are welcome :) Thanx Piotr
Upvotes: 2
Views: 131
Reputation: 414179
Using natural_key() function:
import re
def natural_key(astr):
"""See http://www.codinghorror.com/blog/archives/001018.html"""
return [int(s) if re.match(r'\d+$', s) else s
for s in re.split(r'(\d+)', astr)]
sorted_list = sorted(a, key=lambda d: natural_key(d['cavity']))
[{'cavity': '1K', 'ltg_nr': 'Ltgnr1K'},
{'cavity': '10', 'ltg_nr': 'Ltgnr10'},
{'cavity': '11A', 'ltg_nr': 'Ltgnr11A'},
{'cavity': '11A', 'ltg_nr': 'Ltgnr11A'},
{'cavity': '11A', 'ltg_nr': 'Ltgnr11A'},
{'cavity': '17B', 'ltg_nr': 'Ltgnr17B'},
{'cavity': '20', 'ltg_nr': 'Ltgnr20'},
{'cavity': '21A', 'ltg_nr': 'Ltgnr21A'},
{'cavity': '21B', 'ltg_nr': 'Ltgnr170'},
{'cavity': '21C', 'ltg_nr': 'Ltgnr21C'},
{'cavity': '22', 'ltg_nr': 'Ltgnr22'},
{'cavity': '22AA', 'ltg_nr': 'Ltgnr170'},
{'cavity': '100A', 'ltg_nr': 'Ltgnr170'},
{'cavity': '101', 'ltg_nr': 'Ltgnr170'}]
Upvotes: 3
Reputation: 92569
You are on the right track, but the primary key should probably not be len(k['cavity'])
. That will only consider the length of the string.
I think you need to extract the numeric component and specific have it sort on the number:
import re
sorted(a, key=lambda k: (int(re.sub(r'[A-Z]+$', '', k['cavity'])), k['cavity']) )
[{'cavity': '1K', 'ltg_nr': 'Ltgnr1K'},
{'cavity': '10', 'ltg_nr': 'Ltgnr10'},
{'cavity': '11A', 'ltg_nr': 'Ltgnr11A'},
{'cavity': '11A', 'ltg_nr': 'Ltgnr11A'},
{'cavity': '11A', 'ltg_nr': 'Ltgnr11A'},
{'cavity': '17B', 'ltg_nr': 'Ltgnr17B'},
{'cavity': '20', 'ltg_nr': 'Ltgnr20'},
{'cavity': '21A', 'ltg_nr': 'Ltgnr21A'},
{'cavity': '21B', 'ltg_nr': 'Ltgnr170'},
{'cavity': '21C', 'ltg_nr': 'Ltgnr21C'},
{'cavity': '22', 'ltg_nr': 'Ltgnr22'},
{'cavity': '22AA', 'ltg_nr': 'Ltgnr170'},
{'cavity': '100A', 'ltg_nr': 'Ltgnr170'},
{'cavity': '101', 'ltg_nr': 'Ltgnr170'}]
The regular expression I am using is a bit specific. It expects that capital A-Z letters can be stripped away from the end of each cavity
. I am basing that on your data set. It may need to be altered if cavity
is not <numbers><optional letters>
Upvotes: 1