Reputation: 311
I have a dictionary like:
{'sortingOrder': ['da','ub','ac','rd'], 'listToSort': [{_id:'ub'}, {_id: 'da'}, {_id: 'rd'}, {_id: 'ac'}]}
I want to sort this list so that the id in listToSort matches how sortingOrder is sorted
[{_id:'da'}, {_id: 'ub'}, {_id: 'ac'}, {_id: 'rd'}]
I have to compare a value from listToSort with a value from sortingOrder and sort listToSort accordingly, which has been my main issue.
The id can be any type of character, it just needs to be sorted the same way sortingOrder is sorted.
Sample of the file I have to sort by section title:
{
"storeOrder": ["produce", "bread", "spreads", "deli", "dairy"],
"itemList": [
{
"_id": 9,
"amountNumber": 1,
"amountStr": "2 loaves",
"amountUnits": null,
"estPrice": null,
"listId": 3,
"modified": "2010-10-26 18:11:58",
"name": "white bread",
"notes": null,
"price": null,
"section": "bread",
"status": 1
},
{
"_id": 12,
"amountNumber": 1,
"amountStr": "1 jar",
"amountUnits": null,
"estPrice": null,
"listId": 3,
"modified": "2010-10-26 18:11:58",
"name": "raspberry jam",
"notes": "large bottle",
"price": null,
"section": "spreads",
"status": 0
}
}
Upvotes: 2
Views: 310
Reputation: 180391
You can make an intermediary dict mapping index to string and use that to sort the list of id's:
d1 = {'sortingOrder': ['da','ub','ac','rd'], 'listToSort': [{"id":'ub'}, {"id": 'da'}, {"id": 'rd'}, {"id": 'ac'}]}
l = d1['listToSort']
sort_keys = {s: i for i, s in enumerate(d1["sortingOrder"])}
print(sorted(l, key=lambda d: sort_keys[d["id"]]))
[{'id': 'da'}, {'id': 'ub'}, {'id': 'ac'}, {'id': 'rd'}]
The dicts in l will be ordered by where their values appear in the "sortingOrder"
list.
If you want to sort the list inplace so the original list is sorted just use list.sort
:
l.sort(key=lambda d: sort_keys[d["id"]])
If you want to break ties in your actual data by name then use the name as the secondary key to sort by:
key=lambda d: (sort_keys[d["id"]], d["name"])
Upvotes: 2
Reputation: 37499
You can sort a list of dictionaries (or any object) using one of their attributes or fields by using the key
parameter to sort. The key
parameter expects a function. Each element in the list will be passed to this function, and the return value will be used to sort the elements. In this case, we can create a simple function with lambda
, which enables us to do everything in a single line.
d = {'sortingOrder': ['da','ub','ac','rd'], 'listToSort': [{id:'ub'}, {id: 'da'}, {id: 'rd'}, {id: 'ac'}]}
d['listToSort'].sort(key=lambda x: d['sortingOrder'].index(x['id']))
The one caveat is that it requires that every id
value actually exists in the sortingOrder
list, or else it will throw a ValueError
.
Based off your update, you can sort a list of dictionaries on multiple fields by returning a tuple of the sort fields fron the key
function for sort
d['itemList'].sort(key=lambda x: (d['storeOrder'].index(x['section']), x['name']))
Upvotes: 1
Reputation: 5070
If I understood your task correctly you could just recreate a list. Something like:
_id = xrange(4)
a = {'sortingOrder': ['da','ub','ac','rd'], 'listToSort': [{_id[0]:'ub'}, {_id[1]: 'da'}, {_id[2]: 'rd'}, {_id[3]: 'ac'}]}
arr = [{i.keys()[0]:e} for e in a['sortingOrder'] for i in a['listToSort'] if i.values()[0] == e ]
a['listToSort'] = arr
print a['listToSort']
output
[{1: 'da'}, {0: 'ub'}, {3: 'ac'}, {2: 'rd'}]
UPDATE
a = {'sortingOrder': ['da','ub','ac','rd'], 'listToSort': [{'SortingKey':'ub'}, {'SortingKey': 'da'}, {'SortingKey': 'rd'}, {'SortingKey': 'ac'}]}
arr = [i for e in a['sortingOrder'] for i in a['listToSort'] if i['SortingKey'] == e ]
Upvotes: 1