How to rearrange an Ordered Dictionary with a based on part of the key from a list
Here I am sharing two variants of solution for this.
1. For keys with same prefix, keep the order of initial OrderedDict
Here I am using list comprehension to iterate the order
list and OrderDict
. Based on comparison, we are passing list of tuples with desired order for creating OrderedDict
object:
>>> from collections import OrderedDict
>>> old_OD = OrderedDict([('cat_1',1),
... ('dog_1',2),
... ('cat_2',3),
... ('fish_1',4),
... ('dog_2',5)])
>>> order = ['dog', 'cat', 'fish']
>>> new_OD = OrderedDict([(k,v) for o in order for k, v in old_OD.items() if k.startswith(o+'_')])
# to match the prefix pattern of <key> + "_" ^
where new_OD
will hold:
OrderedDict([('dog_1', 2), ('dog_2', 5), ('cat_1', 1), ('cat_2', 3), ('fish_1', 4)])
2. For keys with same prefix, perform lexicographical sorting of elements
We may modify the above solution using sorted
and itertools.chain
with nested list comprehension to achieve this as:
>>> from itertools import chain
>>> new_OD = OrderedDict(chain(*[sorted([(k,v) for k, v in old_OD.items() if k.startswith(o+'_')]) for o in order]))
where new_OD
will hold:
OrderedDict([('dog_1', 2), ('dog_2', 5), ('cat_1', 1), ('cat_2', 3), ('fish_1', 4)])
You can build a dict that maps each item in order
to its index, and then use the sorted
function with a key function that maps the substring of the each key in old_OD
that appears in the keys of the mapping dict to the corresponding index using the mapping dict:
keys = {k: i for i, k in enumerate(order)}
OrderedDict(sorted(old_OD.items(), key=lambda t: keys.get(next(i for i in t[0].split('_') if i in keys))))
This returns:
OrderedDict([('dog_1', 2), ('dog_2', 5), ('cat_1', 1), ('cat_2', 3), ('fish_1', 4)])