minovsky
minovsky

Reputation: 857

Get sorted list of indices, for a list of dictionaries sorted by a given key

I have a list of dictionaries with multiple keys and I would like to get multiple lists each with the indices of the dictionaries, sorted by a particular key.

For example, I have the following list

a = [{"name": "Zoe", "age": 13}, {"name": "Adam", "age": 31}]

I know that I can do the following

from operator import itemgetter
sorted(a, key=itemgetter("name"))

to get the following

[{'name': 'Adam', 'age': 31}, {'name': 'Zoe', 'age': 13}]

but I really want to be able to get two lists with the indices instead:

[1, 0] # order of the elements in `a` as sorted by name
[0, 1] # order of the elements in `a` as sorted by age

My real dictionary has many more key-value pairs and it's more efficient for me to return a and the additional lists with indices as sorted by different keys rather than multiple sorted lists of a.

Upvotes: 1

Views: 181

Answers (2)

PM 2Ring
PM 2Ring

Reputation: 55469

A simple way to do this is to add an index field to the dicts in your list.

from operator import itemgetter

a = [{'name':"Zoe", 'age':13}, {'name':"Adam", 'age':31}]

for i, d in enumerate(a): 
    d['index'] = i

def get_indices(seq):
    return[d['index'] for d in seq]

by_name = sorted(a, key=itemgetter("name"))
print by_name
print get_indices(by_name)

by_age = sorted(a, key=itemgetter("age"))
print by_age
print get_indices(by_age)

output

[{'index': 1, 'age': 31, 'name': 'Adam'}, {'index': 0, 'age': 13, 'name': 'Zoe'}]
[1, 0]
[{'index': 0, 'age': 13, 'name': 'Zoe'}, {'index': 1, 'age': 31, 'name': 'Adam'}]
[0, 1]

Of course, you don't need to keep the sorted lists of dicts, you could just do

by_name = get_indices(sorted(a, key=itemgetter("name")))

Upvotes: 2

Martijn Pieters
Martijn Pieters

Reputation: 1121714

You can produce a sorted list of indices by producing a range(), and then adjusting the sort key to translate an index to a specific value from a dictionary from the a list:

sorted(range(len(a)), key=lambda i: a[i]['name'])
sorted(range(len(a)), key=lambda i: a[i]['age'])

If you know the keys up front, just loop and produce multiple lists; you could perhaps create a dictionary keyed by each sorting key:

{key: sorted(range(len(a)), key=lambda i: a[i][key]) for key in ('name', 'age')}

The above dictionary comprehension then gives you access to each sorted list based on the sort key alone:

>>> a = [{'name': "Zoe", 'age': 13}, {'name': "Adam", 'age': 31}]
>>> {key: sorted(range(len(a)), key=lambda i: a[i][key]) for key in ('name', 'age')}
{'age': [0, 1], 'name': [1, 0]}

Upvotes: 5

Related Questions