简体   繁体   中英

Sort a list by the sorted order of another list

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
    }
}

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"])

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  ]

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']))

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