Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Get top n key's with Value as dictionary

I have a dictionary like:

data = {'sachin': {'score': 15000, 'out': 100},
        'Dhoni': {'score': 8000, out: 80},
        'Shewag': {'score': 12000, 'out': 150}}

I want to get two players whose score are in top.

So I tried like: key = (key for key,value in dd.items() if value['score'] > 'value').next()

Winded here with no success.

Tried using link:top n keys with highest values in dictionary with tuples as keys

As newbie to Python couldn't get around the perfect solution.

Can someone share some idea on this!!!

Output like:

{'sachin':{'score':15000,'out':100},'Shewag':{'score':12000,'out':150}}

Note: Should be top n player, just for example I need top two but It can be changed later stage.

like image 598
Sandy Avatar asked Jul 06 '16 07:07

Sandy


2 Answers

Quick Answer

Sorting works:

>>> dict(sorted(data.items(), key=lambda x: x[1]['score'], reverse=True)[:2])
{'Shewag': {'out': 150, 'score': 12000},
 'sachin': {'out': 100, 'score': 15000}}

In Steps

You sort the items:

>>> sorted(data.items())
[('Dhoni', {'out': 80, 'score': 8000}),
 ('Shewag', {'out': 150, 'score': 12000}),
 ('sachin', {'out': 100, 'score': 15000})]

This sorts by the names in alphabetical order.

Using a key function defined with lambda sorts by score:

sorted(data.items(), key=lambda x: x[1]['score'])
[('Dhoni', {'out': 80, 'score': 8000}),
 ('Shewag', {'out': 150, 'score': 12000}),
 ('sachin', {'out': 100, 'score': 15000})]

Use reverse to get the largest one first:

sorted(data.items(), key=lambda x: x[1]['score'], reverse=True)
[('sachin', {'out': 100, 'score': 15000}),
 ('Shewag', {'out': 150, 'score': 12000}),
 ('Dhoni', {'out': 80, 'score': 8000})]

Finally, take only the two first items with slicing and convert the list of tuples into a dictionary with dict:

>>> dict(sorted(data.items(), key=lambda x: x[1]['score'], reverse=True)[:2])
{'Shewag': {'out': 150, 'score': 12000},
 'sachin': {'out': 100, 'score': 15000}}

Since a dictionary has no order, you only know that you have two players with top most scores. There is no notion who is first or second. If need this, you can either keep the list of tuples or convert into an OrderedDict to preserve the order:

>>> from collections import OrderedDict
>>> OrderedDict(sorted(data.items(), key=lambda x: x[1]['score'], reverse=True)[:2])
OrderedDict([('sachin', {'out': 100, 'score': 15000}),
             ('Shewag', {'out': 150, 'score': 12000})])

Do It Properly

To make it bit more reusable, you can write a function:

from collections import OrderedDict

def get_top_players(data, n=2, order=False):
    """Get top n players by score. 

    Returns a dictionary or an `OrderedDict` if `order` is true.
    """ 
    top = sorted(data.items(), key=lambda x: x[1]['score'], reverse=True)[:n]
    if order:
        return OrderedDict(top)
    return dict(top)

​

Now you can use it just with your data:

>>> get_top_players(data)
{'Shewag': {'out': 150, 'score': 12000},
 'sachin': {'out': 100, 'score': 15000}}

or set a different number of top players:

>>> get_top_players(data, n=3)
{'Dhoni': {'out': 80, 'score': 8000},
 'Shewag': {'out': 150, 'score': 12000},
 'sachin': {'out': 100, 'score': 15000}}

or get them in order:

>>> get_top_players(data, order=True)
OrderedDict([('sachin', {'out': 100, 'score': 15000}),
             ('Shewag', {'out': 150, 'score': 12000})])
like image 78
Mike Müller Avatar answered Oct 05 '22 22:10

Mike Müller


Your link is right. You must modify it to use it for your case.

The method is:

  1. Sort descending
  2. Get the n first

You can do it with the library heapq

>>> import heapq
>>> heapq.nlargest(2, data.keys(), key=lambda k: data[k]['score'])
['sachin', 'Shewag']

Now you can create a new OrderedDict to store your dict

import heapq
from collections import OderedDict
player_names = heapq.nlargest(2, data.keys(), key=lambda k: data[k]['score'])

ret = OrderedDict((x, data[x]) for x in player_names)
like image 30
qvpham Avatar answered Oct 05 '22 23:10

qvpham