Reputation: 23617
I have a python dictionary:
x = {'a':10.1,'b':2,'c':5}
How do I go about ranking and returning the rank value? Like getting back:
res = {'a':1,c':2,'b':3}
Thanks
Edit:
I am not trying to sort as that can be done via sorted
function in python. I was more thinking about getting the rank values from highest to smallest...so replacing the dictionary values by their position after sorting. 1 means highest and 3 means lowest.
Upvotes: 10
Views: 23459
Reputation: 2447
Using pandas:
import pandas as pd
x = {'a':10.1,'b':2,'c':5}
res = dict(zip(x.keys(), pd.Series(x.values()).rank().tolist()))
Upvotes: 1
Reputation: 2273
Using scipy.stats.rankdata:
[ins] In [55]: from scipy.stats import rankdata
[ins] In [56]: x = {'a':10.1, 'b':2, 'c': 5, 'd': 5}
[ins] In [57]: dict(zip(x.keys(), rankdata([-i for i in x.values()], method='min')))
Out[57]: {'a': 1, 'b': 4, 'c': 2, 'd': 2}
[ins] In [58]: dict(zip(x.keys(), rankdata([-i for i in x.values()], method='max')))
Out[58]: {'a': 1, 'b': 4, 'c': 3, 'd': 3}
@beta, @DSM scipy.stats.rankdata has some other 'methods' for ties also that may be more appropriate to what you are wanting to do with ties.
Upvotes: 2
Reputation: 106528
Pretty simple sort-of simple but kind of complex one-liner.
{key[0]:1 + value for value, key in enumerate(
sorted(d.iteritems(),
key=lambda x: x[1],
reverse=True))}
Let me walk you through it.
enumerate
to give us a natural ordering of elements, which is zero-based. Simply using enumerate(d.iteritems())
will generate a list of tuples that contain an integer, then the tuple which contains a key:value pair from the original dictionary.('a', 0)
, so we want to only get the first element from that. key[0]
accomplishes that.value
.Upvotes: 0
Reputation: 353604
If I understand correctly, you can simply use sorted
to get the ordering, and then enumerate
to number them:
>>> x = {'a':10.1, 'b':2, 'c':5}
>>> sorted(x, key=x.get, reverse=True)
['a', 'c', 'b']
>>> {key: rank for rank, key in enumerate(sorted(x, key=x.get, reverse=True), 1)}
{'b': 3, 'c': 2, 'a': 1}
Note that this assumes that the ranks are unambiguous. If you have ties, the rank order among the tied keys will be arbitrary. It's easy to handle that too using similar methods, for example if you wanted all the tied keys to have the same rank. We have
>>> x = {'a':10.1, 'b':2, 'c': 5, 'd': 5}
>>> {key: rank for rank, key in enumerate(sorted(x, key=x.get, reverse=True), 1)}
{'a': 1, 'b': 4, 'd': 3, 'c': 2}
but
>>> r = {key: rank for rank, key in enumerate(sorted(set(x.values()), reverse=True), 1)}
>>> {k: r[v] for k,v in x.items()}
{'a': 1, 'b': 3, 'd': 2, 'c': 2}
Upvotes: 19
Reputation: 174874
You could do like this,
>>> x = {'a':10.1,'b':2,'c':5}
>>> m = {}
>>> k = 0
>>> for i in dict(sorted(x.items(), key=lambda k: k[1], reverse=True)):
k += 1
m[i] = k
>>> m
{'a': 1, 'c': 2, 'b': 3}
Upvotes: 0
Reputation: 5347
In [23]: from collections import OrderedDict
In [24]: mydict=dict([(j,i) for i, j in enumerate(x.keys(),1)])
In [28]: sorted_dict = sorted(mydict.items(), key=itemgetter(1))
In [29]: sorted_dict
Out[29]: [('a', 1), ('c', 2), ('b', 3)]
In [35]: OrderedDict(sorted_dict)
Out[35]: OrderedDict([('a', 1), ('c', 2), ('b', 3)])
Upvotes: 0
Reputation: 311
One way would be to examine the dictionary for the largest value, then remove it, while building a new dictionary:
my_dict = x = {'a':10.1,'b':2,'c':5}
i = 1
new_dict ={}
while len(my_dict) > 0:
my_biggest_key = max(my_dict, key=my_dict.get)
new_dict[my_biggest_key] = i
my_dict.pop(my_biggest_key)
i += 1
print new_dict
Upvotes: 0
Reputation: 392
First sort by value in the dict, then assign ranks. Make sure you sort reversed, and then recreate the dict with the ranks.
from the previous answer :
import operator
x={'a':10.1,'b':2,'c':5}
sorted_x = sorted(x.items(), key=operator.itemgetter(1), reversed=True)
out_dict = {}
for idx, (key, _) in enumerate(sorted_x):
out_dict[key] = idx + 1
print out_dict
Upvotes: 0