I have a list
of dict
like this:
data = [{"uid": "a1", "name": "b1"},
{"uid": "a3", "name": "b3"},
{"uid": "a4", "name": "b4"},
{"uid": "a5", "name": "b5"}]
Now I want to sort that list
with the order of the uid
field like this:
uid_order = ['a1', 'a5', 'a3', 'a4']
Which means the output should be:
[{"uid": "a1", "name": "b1"},
{"uid": "a5", "name": "b5"},
{"uid": "a3", "name": "b3"},
{"uid": "a4", "name": "b4"}]
Of course, I can create a new empty list
then use 2 for
loops to check and add every element, but is there any elegant way (or better complexity) to do this?
O(n) solution:
>>> [*map({d['uid']: d for d in data}.get, uid_order)]
[{'uid': 'a1', 'name': 'b1'},
{'uid': 'a5', 'name': 'b5'},
{'uid': 'a3', 'name': 'b3'},
{'uid': 'a4', 'name': 'b4'}]
You can sort a list in place with it'ssort
method if you want to avoid making a new list. This will use Timsort, which has O(n log n)
complexity, much better than your suggested O(n^2)
implementation:
uid_order = {k: i for i, k in enumerate(uid_order)}
data.sort(key=uid_order.get)
To speed up lookup into uid_order
, I invert it into a dictionary (invert because a list maps index to item, while you want item to index). Instead of an O(n)
lookup at each evaluation of the key, you have an O(1)
lookup now.
An alternative way to make the dictionary using only function calls:
uid_order = dict(map(reversed, enumerate(uid_order)))
See also: Python Sorting HOW TO
With thesorted
-function you can specify a key that the function should sort after. You want to access the value of the "uid"
key for each dictionary and that value's index in uid_order
determines that dictionary's index in the sorted list:
sorted(data, key = lambda x: uid_order.index(x["uid"]))
What this code means is, each element of the list gets passed to the lambda
-function. The resulting value is used as key to sort after.
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.