Reputation: 1303
So I have a dictionary that looks like this when I print it:
{'10': -10, 'ZT21': 14, 'WX21': 12, '2': 15, '5': -3, 'UM': -25}
I want to sort these in a custom manner, which I define. Let's say the way I want it to be sorted (by key) is ZT21, 10, WX21, UM, 5, 2
.
Anyone know how to go about sorting out a dictionary in a predefined/custom manner? What I am doing is getting this dictionary from a database, and it can come out with over 20 keys, all of which have a specific order. The order is always set, but sometimes certain keys/values wouldn't be in the dictionary. So this could happen too:
{'ZT21': 14, 'WX21': 12, '2': 15, '5': -3, 'UM': -25}
sorted (by key) is ZT21, 10, WX21, UM, 5, 2
.
So the 10 isn't there in this example, but the sorting I need is still the same, the 10 would just be absent.
Any ideas?
Upvotes: 24
Views: 34060
Reputation: 304147
Updated answer for Python 3.6+
>>> d = {'10': -10, 'ZT21': 14, 'WX21': 12, '2': 15, '5': -3, 'UM': -25}
>>> keyorder = ['ZT21', '10', 'WX21', 'UM', '5', '2']
>>> {k: d[k] for k in keyorder if k in d}
{'ZT21': 14, '10': -10, 'WX21': 12, 'UM': -25, '5': -3, '2': 15}
Legacy answer:
Dictionaries in Python are unordered (before Python3.6). You can get the results you need as a list
>>> d = {'10': -10, 'ZT21': 14, 'WX21': 12, '2': 15, '5': -3, 'UM': -25}
>>> keyorder = ['ZT21', '10', 'WX21', 'UM', '5', '2']
>>> sorted(d.items(), key=lambda i:keyorder.index(i[0]))
[('ZT21', 14), ('10', -10), ('WX21', 12), ('UM', -25), ('5', -3), ('2', 15)]
or as an OrderedDict
>>> from collections import OrderedDict
>>> OrderedDict(sorted(d.items(), key=lambda i:keyorder.index(i[0])))
OrderedDict([('ZT21', 14), ('10', -10), ('WX21', 12), ('UM', -25), ('5', -3), ('2', 15)])
If you are doing a lot of these, it will be more efficient to use a dict
for the keyorder
>>> keyorder = {k:v for v,k in enumerate(['ZT21', '10', 'WX21', 'UM', '5', '2'])}
>>> OrderedDict(sorted(d.items(), key=lambda i:keyorder.get(i[0])))
OrderedDict([('ZT21', 14), ('10', -10), ('WX21', 12), ('UM', -25), ('5', -3), ('2', 15)])
Upvotes: 64
Reputation: 41
You can sort it using OrderedDict and by specifying your Custom-order.
def customsort(dict1 , key_order):
items = [dict1[k] if k in dict1.keys() else 0 for k in key_order]
sorted_dict = OrderedDict()
for i in range(len(key_order)):
sorted_dict[key_order[i]] = items[i]
return sorted_dict
key_order = [ "monday" ,"tuesday" ,"wednesday" ,"thursday" ,"friday" ,"saturday"]
dict1 ={"monday" : 10 , "thursday" :12 , "wednesday" : 34}
sorted_dicti = customsort(dict1,key_order)
print(sorted_dicti)
customsort() sorts given dictionary(dict1) by order(key_order) passed by user.
items = [dict1[k] if k in dict1.keys() else 0 for k in key_order]
It will check if the given key is in dict1 if it is there then put value specified in dict1 else put value as 0.
OrderedDict([('monday', 10), ('tuesday', 0), ('wednesday', 34), ('thursday', 12), ('friday', 0), ('saturday', 0)])
Upvotes: 4
Reputation: 3984
I had exactly the same problem and devised a lightweight general solution:
from collections import OrderedDict
def make_custom_sort(orders):
orders = [{k: -i for (i, k) in enumerate(reversed(order), 1)} for order in orders]
def process(stuff):
if isinstance(stuff, dict):
l = [(k, process(v)) for (k, v) in stuff.items()]
keys = set(stuff)
for order in orders:
if keys.issuperset(order):
return OrderedDict(sorted(l, key=lambda x: order.get(x[0], 0)))
return OrderedDict(sorted(l))
if isinstance(stuff, list):
return [process(x) for x in stuff]
return stuff
return process
First, you create an instance of a custom-order sorting function:
custom_sort = make_custom_sort([ ['ZT21', '10', 'WX21', 'UM', '5', '2'] ])
Now, the actual sorting:
result = custom_sort(my_dataset)
The missing keys are rejected at the end in an unspecified order. Note that this closure is recursive. As indicated by the double brackets, you could specify as many sort orders as the various dictionaries nested in your structure would require.
Project on GitHub: https://github.com/laowantong/customsort
Upvotes: 0
Reputation: 251373
Dictionaries are inherently unordered, so you can't directly sort the dictionary. You can sort the key/value pairs by sorting someDict.items()
and passing in a key function just like you would when sorting anything else, but you will get a sorted list and not a dictionary. See previous questions on dictionary sorting: Python: sorting a dictionary of lists and Dictionary sorting by key length for instance.
Upvotes: 1
Reputation: 798616
You can't. Use a collections.OrderedDict
instead.
Upvotes: 2