Munshine
Munshine

Reputation: 432

Sort a list of dict with a key from another list of dict

In the following example, I would like to sort the animals by the alphabetical order of their category, which is stored in an order dictionnary.

category = [{'uid': 0, 'name': 'mammals'},
            {'uid': 1, 'name': 'birds'},
            {'uid': 2, 'name': 'fish'},
            {'uid': 3, 'name': 'reptiles'},
            {'uid': 4, 'name': 'invertebrates'},
            {'uid': 5, 'name': 'amphibians'}]

animals = [{'name': 'horse', 'category': 0},
           {'name': 'whale', 'category': 2},
           {'name': 'mollusk', 'category': 4},
           {'name': 'tuna ', 'category': 2},
           {'name': 'worms', 'category': 4},
           {'name': 'frog', 'category': 5},
           {'name': 'dog', 'category': 0},
           {'name': 'salamander', 'category': 5},
           {'name': 'horse', 'category': 0},
           {'name': 'octopus', 'category': 4},
           {'name': 'alligator', 'category': 3},
           {'name': 'monkey', 'category': 0},
           {'name': 'kangaroos', 'category': 0},
           {'name': 'salmon', 'category': 2}]

sorted_animals = sorted(animals, key=lambda k: (k['category'])

How could I achieve this? Thanks.

Upvotes: 0

Views: 127

Answers (2)

SpghttCd
SpghttCd

Reputation: 10860

imo your category structure is far too complicated - at least as long as the uid is nothing but the index, you could simply use a list for that:

category = [c['name'] for c in category]
# ['mammals', 'birds', 'fish', 'reptiles', 'invertebrates', 'amphibians']

sorted_animals = sorted(animals, key=lambda k: category[k['category']])

#[{'name': 'frog', 'category': 5}, {'name': 'salamander', 'category': 5}, {'name': 'whale', 'category': 2}, {'name': 'tuna ', 'category': 2}, {'name': 'salmon', 'category': 2}, {'name': 'mollusk', 'category': 4}, {'name': 'worms', 'category': 4}, {'name': 'octopus', 'category': 4}, {'name': 'horse', 'category': 0}, {'name': 'dog', 'category': 0}, {'name': 'horse', 'category': 0}, {'name': 'monkey', 'category': 0}, {'name': 'kangaroos', 'category': 0}, {'name': 'alligator', 'category': 3}]                                                

Upvotes: 0

Martijn Pieters
Martijn Pieters

Reputation: 1122122

You are now sorting on the category id. All you need to do is map that id to a lookup for a given category name.

Create a dictionary for the categories first so you can directly map the numeric id to the associated name from the category list, then use that mapping when sorting:

catuid_to_name = {c['uid']: c['name'] for c in category}

sorted_animals = sorted(animals, key=lambda k: catuid_to_name[k['category']])

Demo:

>>> from pprint import pprint
>>> category = [{'uid': 0, 'name': 'mammals'},
...             {'uid': 1, 'name': 'birds'},
...             {'uid': 2, 'name': 'fish'},
...             {'uid': 3, 'name': 'reptiles'},
...             {'uid': 4, 'name': 'invertebrates'},
...             {'uid': 5, 'name': 'amphibians'}]
>>> animals = [{'name': 'horse', 'category': 0},
...            {'name': 'whale', 'category': 2},
...            {'name': 'mollusk', 'category': 4},
...            {'name': 'tuna ', 'category': 2},
...            {'name': 'worms', 'category': 4},
...            {'name': 'frog', 'category': 5},
...            {'name': 'dog', 'category': 0},
...            {'name': 'salamander', 'category': 5},
...            {'name': 'horse', 'category': 0},
...            {'name': 'octopus', 'category': 4},
...            {'name': 'alligator', 'category': 3},
...            {'name': 'monkey', 'category': 0},
...            {'name': 'kangaroos', 'category': 0},
...            {'name': 'salmon', 'category': 2}]
>>> catuid_to_name = {c['uid']: c['name'] for c in category}
>>> pprint(catuid_to_name)
{0: 'mammals',
 1: 'birds',
 2: 'fish',
 3: 'reptiles',
 4: 'invertebrates',
 5: 'amphibians'}
>>> sorted_animals = sorted(animals, key=lambda k: catuid_to_name[k['category']])
>>> pprint(sorted_animals)
[{'category': 5, 'name': 'frog'},
 {'category': 5, 'name': 'salamander'},
 {'category': 2, 'name': 'whale'},
 {'category': 2, 'name': 'tuna '},
 {'category': 2, 'name': 'salmon'},
 {'category': 4, 'name': 'mollusk'},
 {'category': 4, 'name': 'worms'},
 {'category': 4, 'name': 'octopus'},
 {'category': 0, 'name': 'horse'},
 {'category': 0, 'name': 'dog'},
 {'category': 0, 'name': 'horse'},
 {'category': 0, 'name': 'monkey'},
 {'category': 0, 'name': 'kangaroos'},
 {'category': 3, 'name': 'alligator'}]

Note that within each category, the dictionaries have been left in relative input order. You could return a tuple of values from the sorting key to further apply a sorting order within each category, e.g.:

sorted_animals = sorted(
    animals,
    key=lambda k: (catuid_to_name[k['category']], k['name'])
)

would sort by animal name within each category, producing:

>>> pprint(sorted(animals, key=lambda k: (catuid_to_name[k['category']], k['name'])))
[{'category': 5, 'name': 'frog'},
 {'category': 5, 'name': 'salamander'},
 {'category': 2, 'name': 'salmon'},
 {'category': 2, 'name': 'tuna '},
 {'category': 2, 'name': 'whale'},
 {'category': 4, 'name': 'mollusk'},
 {'category': 4, 'name': 'octopus'},
 {'category': 4, 'name': 'worms'},
 {'category': 0, 'name': 'dog'},
 {'category': 0, 'name': 'horse'},
 {'category': 0, 'name': 'horse'},
 {'category': 0, 'name': 'kangaroos'},
 {'category': 0, 'name': 'monkey'},
 {'category': 3, 'name': 'alligator'}]

Upvotes: 3

Related Questions