Python, конвертировать словарь в отсортированный список по значению вместо ключа

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

adict = defaultdict(int)

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

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

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

someval => 2
anotherval => 1

Ответы

Ответ 1

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

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

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

[(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, однако, также является разумной альтернативой.

Ответ 2

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

from operator import itemgetter

sorted(adict.iteritems(), key=itemgetter(1), reverse=True)

Ответ 3

Просто отсортируйте полученный dict по значениям:

for k, v in sorted(adict.items(), key=lambda kv: kv[1], reverse=True):
    print("%s => %s" % (k,v))

Ответ 4

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

 

Ответ 5

Если вы используете новейший 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, которая должна быть выпущена.

Ответ 6

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

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

Повторение эксперимента с диапазоном (-n, n + 1) (окно Windows, 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 idiom". Поместите их близко друг к другу для удобства сравнения:

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

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

Ответ 7

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

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