Словарь Python 2.5 для словаря 2
У меня есть словарь из 200 000 элементов (ключи - это строки, а значения - целые числа).
Каков наилучший/самый pythonic способ распечатать элементы, отсортированные по нисходящему значению, а затем по возрастающей клавише (т.е. по 2 ключам)?
a={ 'keyC':1, 'keyB':2, 'keyA':1 }
b = a.items()
b.sort( key=lambda a:a[0])
b.sort( key=lambda a:a[1], reverse=True )
print b
>>>[('keyB', 2), ('keyA', 1), ('keyC', 1)]
Ответы
Ответ 1
Вы не можете сортировать словари. Вам нужно отсортировать список элементов.
Предыдущие версии были неправильными. Когда у вас есть числовое значение, его легко сортировать в обратном порядке. Они сделают это. Но это не общее. Это работает только потому, что значение является числовым.
a = { 'key':1, 'another':2, 'key2':1 }
b= a.items()
b.sort( key=lambda a:(-a[1],a[0]) )
print b
Здесь альтернатива, используя явную функцию вместо лямбда и cmp вместо ключевой опции.
def valueKeyCmp( a, b ):
return cmp( (-a[1], a[0]), (-b[1], b[0] ) )
b.sort( cmp= valueKeyCmp )
print b
Более общее решение - это фактически два отдельных вида
b.sort( key=lambda a:a[1], reverse=True )
b.sort( key=lambda a:a[0] )
print b
Ответ 2
data = { 'keyC':1, 'keyB':2, 'keyA':1 }
for key, value in sorted(data.items(), key=lambda x: (-1*x[1], x[0])):
print key, value
Ответ 3
Самый пифонический способ сделать это - узнать немного больше о реальных данных - в частности, о максимальном значении, которое вы можете иметь, - и затем сделать это следующим образом:
def sortkey((k, v)):
return (maxval - v, k)
items = thedict.items()
items.sort(key=sortkey)
но если вы уже знаете максимальное значение, поиск максимального значения означает, что цикл через дополнительное время (с max(thedict.itervalues())
) может быть дорогим. Альтернативно, версия keyfunc решения S.Lott:
def sortkey((k, v)):
return (-v, k)
items = thedict.items()
items.sort(key=sortkey)
Альтернативой, которая не заботится о типах, будет функция сравнения:
def sortcmp((ak, av), (bk, bv)):
# compare values 'in reverse'
r = cmp(bv, av)
if not r:
# and then keys normally
r = cmp(ak, bk)
return r
items = thedict.items()
items.sort(cmp=sortcmp)
и это решение действительно работает для любого типа ключа и значения, которые вы хотите смешивать по возрастанию и убыванию сортировки с одним и тем же ключом. Если вы цените краткость, вы можете написать sortcmp как:
def sortcmp((ak, av), (bk, bv)):
return cmp((bk, av), (ak, bv))
Ответ 4
Вы можете использовать что-то вроде этого:
dic = {'aaa':1, 'aab':3, 'aaf':3, 'aac':2, 'aad':2, 'aae':4}
def sort_compare(a, b):
c = cmp(dic[b], dic[a])
if c != 0:
return c
return cmp(a, b)
for k in sorted(dic.keys(), cmp=sort_compare):
print k, dic[k]
Не знаю, как это pythonic:)
Ответ 5
Основываясь на решениях Томаса Ваутерса и Рикардо Рейеса:
def combine(*cmps):
"""Sequence comparisons."""
def comparator(a, b):
for cmp in cmps:
result = cmp(a, b):
if result:
return result
return 0
return comparator
def reverse(cmp):
"""Invert a comparison."""
def comparator(a, b):
return cmp(b, a)
return comparator
def compare_nth(cmp, n):
"""Compare the n'th item from two sequences."""
def comparator(a, b):
return cmp(a[n], b[n])
return comparator
rev_val_key_cmp = combine(
# compare values, decreasing
reverse(compare_nth(1, cmp)),
# compare keys, increasing
compare_nth(0, cmp)
)
data = { 'keyC':1, 'keyB':2, 'keyA':1 }
for key, value in sorted(data.items(), cmp=rev_val_key_cmp):
print key, value
Ответ 6
>>> keys = sorted(a, key=lambda k: (-a[k], k))
или
>>> keys = sorted(a)
>>> keys.sort(key=a.get, reverse=True)
затем
print [(key, a[key]) for key in keys]
[('keyB', 2), ('keyA', 1), ('keyC', 1)]