3

I have a dictionary with student-name and marks

dict1 = {'name1': 34, 'name2':45, 'name3': 98, 'name4':34, 'name5': 66}

I want to get the top 10 student names along with their marks from the above dict.

Result:

name3 98
name5 66
name2 45
name1 34
name4 34

In case of multiple keys for same values, keys must be in alphabetical order (Ex: name1 and name4 are in alphabetical order for same value 34)

How to get it done ?

Kumar
  • 314
  • 3
  • 5
  • 16

2 Answers2

11

Use heapq.nlargest():

from heapq import nlargest
from operator import itemgetter

for name, score in nlargest(10, dictionary.iteritems(), key=itemgetter(1)):
    print name, score

Demo:

>>> for name, score in nlargest(10, dictionary.iteritems(), key=itemgetter(1)):
...     print name, score
... 
name3 98
name5 66
name2 45
name4 34
name1 34

Note that because your sample dictionary is smaller than the top n you want, you could just as well have used sorted():

for name, score in sorted(dictionary.iteritems(), key=itemgetter(1), reverse=True):
    print name, score

but for any top n where n is smaller than len(dictionary) heapq is the better choice.

Alternatively, use a collections.Counter() object, it has a .most_common() method that gives you exactly that; the highest n scoring elements in the counter:

>>> scores = Counter(dictionary)
>>> scores
Counter({'name3': 98, 'name5': 66, 'name2': 45, 'name4': 34, 'name1': 34})
>>> scores.most_common(3)
[('name3', 98), ('name5', 66), ('name2', 45)]
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
7

Naive solution

You can write this in plain python:

>>> names = {'name1': 34, 'name2':45, 'name3': 98, 'name4':34, 'name5': 66}
>>> sorted_names = sorted(names.iteritems(), key=lambda (k, v): (-v, k))[:10]
>>> sorted_names
[('name3', 98), ('name5', 66), ('name2', 45), ('name1', 34), ('name4', 34)]

sorted takes a key for sorting as the comparison

Then just print them as you wish:

>>> for name, score in sorted_names:
...     print name, score
...
name3 98
name5 66
name2 45
name1 34
name4 34

Or just do it all at once:

>>> for name, score in sorted(names.iteritems(), key=lambda (k, v): (-v, k))[:10]:
...     print name, score
...
name3 98
name5 66
name2 45
name1 34
name4 34

Inspired by @Martijn Pieters' answer

Using heapq and in particular heapq.nsmallest you can have a much more elegant solution:

>>> from heapq import nsmallest
>>> for name, score in nsmallest(10, names.iteritems(), key=lambda (k, v): (-v, k)):
...     print name, score
...
name3 98
name5 66
name2 45
name1 34
name4 34

What I like about this solution is that nsmallest could be implemented intelligently. It could be something like a lazy implementation like is described in this answer to Lazy Evaluation and Time Complexity. And so, you'd only do the minimum amount of work. Whereas the naive solution would have to sort the entire iterable before getting the first 10.

Community
  • 1
  • 1
joneshf
  • 2,296
  • 1
  • 20
  • 27