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