=== Обновление после изменения / уточнения спецификаций ===
# coding: ascii
def ranks_from_scores(sorted_scores):
"""sorted_scores: a list of tuples (object_id, score), sorted by score DESCENDING
return a mapping of object IDs to ranks
"""
ranks = {}
previous_score = object()
for index, (obj_id, score) in enumerate(sorted_scores):
if score != previous_score:
previous_score = score
rank = index + 1
ranks[obj_id] = rank
return ranks
from operator import itemgetter
import pprint
scores0 = dict([
('Apolo Ohno', 0),
('Shanie Davis', -1),
('Bodie Miller', -2),
('Lindsay Vohn', -3),
('Shawn White', -3)
])
scores1 = {
'lorem': 100,
'ipsum': 200,
'dolor': 300,
'sit': 300,
'amet': 300,
'quia': 400,
'consectetur': 500,
'adipiscing': 500,
'elit': 600,
}
scores2 = {
'lorem': 100,
'ipsum': 200,
'dolor': 300,
'sit': 300,
'amet': 300,
'quia': 400,
'consectetur': 500,
'adipiscing': 500,
'elit': 6000,
}
import pprint
funcs = (ranks_from_scores, ) # Watch this space!
tests = (scores0, scores1, scores2)
for test in tests:
print
test_list = sorted(test.items(), key=itemgetter(1), reverse=True)
print "Input:", test_list
for func in funcs:
result = func(test_list)
print "%s ->" % func.__name__
pprint.pprint(result)
Результаты:
Input: [('Apolo Ohno', 0), ('Shanie Davis', -1), ('Bodie Miller', -2), ('Lindsay
Vohn', -3), ('Shawn White', -3)]
ranks_from_scores ->
{'Apolo Ohno': 1,
'Bodie Miller': 3,
'Lindsay Vohn': 4,
'Shanie Davis': 2,
'Shawn White': 4}
Input: [('elit', 600), ('consectetur', 500), ('adipiscing', 500), ('quia', 400),
('dolor', 300), ('sit', 300), ('amet', 300), ('ipsum', 200), ('lorem', 100)]
ranks_from_scores ->
{'adipiscing': 2,
'amet': 5,
'consectetur': 2,
'dolor': 5,
'elit': 1,
'ipsum': 8,
'lorem': 9,
'quia': 4,
'sit': 5}
Input: [('elit', 6000), ('consectetur', 500), ('adipiscing', 500), ('quia', 400)
, ('dolor', 300), ('sit', 300), ('amet', 300), ('ipsum', 200), ('lorem', 100)]
ranks_from_scores ->
{'adipiscing': 2,
'amet': 5,
'consectetur': 2,
'dolor': 5,
'elit': 1,
'ipsum': 8,
'lorem': 9,
'quia': 4,
'sit': 5}
=== оригинальное представление ===
В этом коде предполагается, что вы действительно хотите, чтобы наивысший балл получал звание 1, а не наименьший балл для получения звания 1 (или 0!).
# coding: ascii
def ranks_from_scores(scores, debug=False):
"""scores (a mapping of object IDs to scores)
return a mapping of object IDs to ranks
"""
alist = [(v, k) for k, v in scores.items()]
alist.sort(reverse=True)
if debug: print 'alist:', alist
bdict = {}
previous_score = object()
for posn, (score, obj_id) in enumerate(alist):
if score != previous_score:
previous_score = score
rank = posn + 1
bdict[obj_id] = rank
if debug:
print 'bdict:', bdict
blist = [(v, k) for k, v in bdict.items()]
print 'blist:', sorted(blist)
return bdict
ranks_from_scores(
{'q': 10, 'w': 20, 'e': 20, 'r': 20, 't': 30},
debug=True,
)
Выход:
alist: [(30, 't'), (20, 'w'), (20, 'r'), (20, 'e'), (10, 'q')]
bdict: {'q': 5, 'r': 2, 'e': 2, 't': 1, 'w': 2}
blist: [(1, 't'), (2, 'e'), (2, 'r'), (2, 'w'), (5, 'q')]