简体   繁体   中英

sort a list of dictionaries based on explicitly defined order of keys

I have a list of dictionary for ex:

names = [{'Mark':'Volvo'}, {'John':'BMW'}, {'Eliza':'Merci'}, {'Calen':'Audi'}]

I would like to set the explicit ordering by the key names of the dictionary.

For example if I give this order:

['John','Mark','Calen','Eliza']

The expected output would be:

[{'John':'BMW'},{'Mark':'Volvo'},{'Calen':'Audi'},{'Eliza':'Merci'}]

I want to add a custom logic order. To be displayed through the template by their names, based on how I defined the order of their names.

Similar to Is there a way to sort a list of string by a “predicate” list? : Since names is a list of dictionaries with just one key-value pair each, use the index of the person's name in the order list as the key for the sort:

>>> names = [{'Mark': 'Volvo'}, {'John': 'BMW'}, {'Eliza': 'Merci'}, {'Calen' :'Audi'}]
>>> order = ['John', 'Mark', 'Calen', 'Eliza']
>>>
>>> # with `sorted()`
>>> sorted(names, key=lambda d: order.index(list(d.keys())[0]))
[{'John': 'BMW'}, {'Mark': 'Volvo'}, {'Calen': 'Audi'}, {'Eliza': 'Merci'}]
>>>
>>> # or with `list.sort()`
>>> names.sort(key=lambda d: order.index(list(d.keys())[0]))
>>> names
[{'John': 'BMW'}, {'Mark': 'Volvo'}, {'Calen': 'Audi'}, {'Eliza': 'Merci'}]

dict.keys() is not not subscriptable, so dict.keys()[0] doesn't work. So first convert that to a list and then use its one-and-only key list(dict.keys())[0] . That would give 'Mark', 'John', etc. Then get the index of that person's name in the order list. Note: it will fail if a person is not listed in order .

Even if names is a list of dictionaries with more than one key-value pair each, as long as the person's name is the first key , it will still work as of Python 3.7/3.6. See the note below this item :

Changed in version 3.7: Dictionary order is guaranteed to be insertion order. This behavior was an implementation detail of CPython from 3.6.

>>> names = [{'Mark': 'Volvo', 'age': 30},
...          {'John': 'BMW', 'age': 40},
...          {'Eliza': 'Merci', 'age': 50},
...          {'Calen': 'Audi', 'age': 60}]
>>> sorted(names, key=lambda d: order.index(list(d.keys())[0]))
[{'John': 'BMW', 'age': 40}, {'Mark': 'Volvo', 'age': 30}, {'Calen': 'Audi', 'age': 60}, {'Eliza': 'Merci', 'age': 50}]
>>>

First, if your dictionaries only have one entry, tuples seem to be a better choice for this data:

>>> names = [('Mark', 'Volvo'), ('John', 'BMW'), ('Eliza', 'Merci'), ('Calen', 'Audi')]

Now, given this order:

>>> order = ['John', 'Mark', 'Calen', 'Eliza']

you can create a dict that maps the names to the indices:

>>> order_map = { k: v for v, k in enumerate(order) }
>>> order_map
{'John': 0, 'Mark': 1, 'Calen': 2, 'Eliza': 3}

and use it in a key function for sort:

>>> names.sort(key=lambda v: order_map[v[0]])
>>> names
[('John', 'BMW'), ('Mark', 'Volvo'), ('Calen', 'Audi'), ('Eliza', 'Merci')]
names = [{'Mark':'Volvo'}, {'John':'BMW'}, {'Eliza':'Merci'}, {'Calen':'Audi'}]
ordered_keys = ['John','Mark','Calen','Eliza']

sorted_names = [name for key in ordered_keys for name in names if key in name]

It iterates over the ordered_keys in order and extracts any name in the list of dict that has that key.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM