Toren
Toren

Reputation: 6854

Get value indices from dictionary

I have an OrderedDict:

from collections import OrderedDict
d = OrderedDict([('r', 1), ('s', 5), ('a', 3), ('n', 7), ('y', 2)])

I'd like to get indices of dictionary values according to values range. For example, indices of dictionary d should be array (or np.array), like following:

indices
array([ 0, 3, 2, 4, 1 ], dtype=int64) 

index 4 is a biggest value in dictionary, index 0 is smallest value

I tried :

indices = np.argsort(d.values)

Upvotes: 1

Views: 161

Answers (4)

user2285236
user2285236

Reputation:

Since you've tried with argsort:

np.argsort(d.values()).argsort()
Out[50]: array([0, 3, 2, 4, 1], dtype=int64)

So argsort does not actually return their orders but it returns the indices that would sort that array. Calling argsort on that result does what you want.

Upvotes: 2

Toren
Toren

Reputation: 6854

At the end I forgot to put () after values , so I used indices = np.argsort(d.values())

Upvotes: 0

Alex Hall
Alex Hall

Reputation: 36033

The other answer is nice and simple but is O(n^2) as each .index is O(n). You can precompute the indices in a dictionary so that the index lookups are O(1), making the whole thing O(nlogn) as the sort is the most expensive part. If d is large enough this will be a very important difference.

>>> from itertools import izip
>>> indices = dict(izip(sorted_values, xrange(len(d))))
>>> indices
{1: 0, 2: 1, 3: 2, 5: 3, 7: 4}
>>> [indices[v] for v in d.itervalues()]
[0, 3, 2, 4, 1]

Here I've used xrange instead of range, izip instead of zip, and itervalues instead of values for memory efficiency.

Upvotes: 0

Selcuk
Selcuk

Reputation: 59228

You can use a list comprehension to implement this:

>>> values = d.values()
>>> sorted_values = sorted(values)
>>> [sorted_values.index(item) for item in values]
[0, 3, 2, 4, 1]

Upvotes: 2

Related Questions