Python, преобразовать словарь в отсортированный список по значению вместо ключа - PullRequest
15 голосов
/ 16 декабря 2009

У меня есть коллекция collection.defaultdict (int), которую я создаю, чтобы вести подсчет того, сколько раз ключ появляется в наборе данных. Позже я хочу иметь возможность отсортировать его (очевидно, сначала превратив в список) по убыванию, упорядочив сначала по самым высоким значениям. Я создал свой словарь следующим образом:

adict = defaultdict(int)

позже я сделаю кучу:

adict['someval'] += 1
adict['anotherval'] +=1
adict['someval'] += 1

В идеале после этого я хотел бы получить отпечаток:

someval => 2
anotherval => 1

Ответы [ 7 ]

42 голосов
/ 16 декабря 2009

Чтобы отсортировать словарь:

from operator import itemgetter

sorted(adict.iteritems(), key=itemgetter(1), reverse=True)
37 голосов
/ 16 декабря 2009

Ключи диктовки, отсортированные по соответствующим значениям, лучше всего получить как

sorted(adict, key=adict.get, reverse=True)

поскольку вам нужны пары ключ / значение, вы можете работать с элементами, как предлагают все другие ответы, или (использовать изящный adict.get связанный метод вместо itemgetters или странных лямбд; -),

[(k, adict[k]) for k in sorted(adict, key=adict.get, reverse=True)]

Редактировать : с точки зрения производительности в этом нет особого смысла:

$ python -mtimeit -s'adict=dict((x,x**2) for x in range(-5,6))' '[(k, adict[k]) for k in sorted(adict, key=adict.get, reverse=True)]'
100000 loops, best of 3: 10.8 usec per loop
$ python -mtimeit -s'adict=dict((x,x**2) for x in range(-5,6)); from operator import itemgetter' 'sorted(adict.iteritems(), key=itemgetter(1), reverse=True)'
100000 loops, best of 3: 9.66 usec per loop
$ python -mtimeit -s'adict=dict((x,x**2) for x in range(-5,6))' 'sorted(adict.iteritems(), key=lambda (k,v): v, reverse=True)'
100000 loops, best of 3: 11.5 usec per loop

Итак, решение на основе .get на полпути по производительности между двумя items - немного медленнее, чем itemgetter, немного быстрее, чем lambda. В случаях «узкого места», когда эти микросекундные дроби имеют решающее значение для вас, непременно сосредоточьтесь на этом. В обычных случаях, когда эта операция - только один шаг в какой-то более крупной задаче, а микросекунда более или менее не имеет большого значения, сосредоточение на простоте идиомы get также является разумной альтернативой.

4 голосов
/ 16 декабря 2009

Просто отсортируйте полученную информацию по значениям:

for k, v in sorted(adict.items(), key=lambda kv: kv[1], reverse=True):
    print("%s => %s" % (k,v))
3 голосов
/ 18 декабря 2009

Примечание: я добавляю это как ответ, чтобы это было видно. Я не хочу голосов. Если вы хотите кого-то поднять, проголосуйте за Надю.

В настоящее время принятый ответ дает временные результаты, основанные на простом наборе данных (размер == 6 - (-5) == 11). Различия в стоимости различных методов маскируются накладными расходами. Вариант использования, например, какие слова встречаются чаще всего в тексте или наиболее часто встречающиеся имена в списке членов или в переписи, включает наборы данных гораздо большего размера.

Повтор эксперимента с диапазоном (-n, n + 1) (Windows box, Python 2.6.4, все время в микросекундах):

n = 5: 11,5, 9,34, 11,3
n = 50: 65,5, 46,2, 68,1
n = 500: 612, 423, 614

Эти результаты НЕ "немного" отличаются. Ответ от предметника - явный победитель по скорости.

Было также упомянуто о " простоте get идиомы ". Соединение их для удобства сравнения:

[(k, adict[k]) for k in sorted(adict, key=adict.get, reverse=True)] sorted(adict.iteritems(), key=itemgetter(1), reverse=True)

Идиома get не только дважды ищет диктат (как указал Дж. Ф. Себастьян), но и составляет один список (результат sorted()), а затем перебирает этот список для создания списка результатов. Я бы назвал это барокко, а не просто . YMMV.

2 голосов
/ 16 декабря 2009

Если вы используете новейшую версию Python 2.7 alpha, то вы можете использовать класс Counter в модуле коллекций:

c = Counter()

c['someval'] += 1
c['anotherval'] += 1
c['someval'] += 1

print c.most_common()

печатает в правильном порядке:

[('someval', 2), ('anotherval', 1)]

Код, используемый в 2.7: уже доступен , и есть версия , адаптированная для 2.5 . Возможно, вы захотите использовать его, чтобы поддерживать совместимость с исходной версией stdlib, которая скоро будет выпущена.

2 голосов
/ 16 декабря 2009
from collections import defaultdict
adict = defaultdict(int)

adict['a'] += 1
adict['b'] += 3
adict['c'] += 5
adict['d'] += 2

for key, value in sorted(adict.items(), lambda a, b: cmp(a[1], b[1]), reverse=True):
    print "%r => %r" % (key, value)

>>> 
'c' => 5
'b' => 3
'd' => 2
'a' => 1

0 голосов
/ 16 декабря 2009

«Инвертировать» словарь.

from collections import defaultdict
inv_dict = defaultdict( list )
for key, value in adict:
    inv_dict[value].append( key )
max_value= max( inv_dict.keys() )

Набор ключей с максимальным вхождением -

inv_dict[max_value] 

Набор ключей в порядке убывания по вхождению -

for value, key_list in sorted( inv_dict ):
    print key_list, value
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...