Как отсортировать словарь, имеющий ключи как строку чисел в Python
У меня есть словарь:
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 }
Я хочу отсортировать этот словарь по ключу, чтобы он выглядел так:
a = {'1':64,'6':5,'67':7,'88':3, '100':12,'test':34 }
6 ответов
Как и все остальные, словари имеют собственный порядок, и вы не можете просто отсортировать их, как список.
Я хотел бы добавить одну вещь: если вы просто хотите просмотреть элементы словаря в отсортированном порядке, это просто:
for k in sorted(a):
print k, a[k] # or whatever.
Если вы хотели бы иметь понимание списка (по Алекс):
sortedlist = [(k, a[k]) for k in sorted(a)]
Я хотел бы отметить, что Алекс использует key=int
не будет работать с вашим примером, потому что один из ваших ключей 'test'
, Если вы действительно хотите, чтобы числа сортировались перед нечисловыми значениями, вам придется передать cmp
функция:
def _compare_keys(x, y):
try:
x = int(x)
except ValueError:
xint = False
else:
xint = True
try:
y = int(y)
except ValueError:
if xint:
return -1
return cmp(x.lower(), y.lower())
# or cmp(x, y) if you want case sensitivity.
else:
if xint:
return cmp(x, y)
return 1
for k in sorted(a, cmp=_compare_keys):
print k, a[k] # or whatever.
Или, может быть, вы достаточно знаете о своих ключах, чтобы написать функцию для преобразования их в строку (или другой объект), которая сортирует правильно:
# Won't work for integers with more than this many digits, or negative integers.
MAX_DIGITS = 10
def _keyify(x):
try:
xi = int(x)
except ValueError:
return 'S{0}'.format(x)
else:
return 'I{0:0{1}}'.format(xi, MAX_DIGITS)
for k in sorted(a, key=_keyify):
print k, a[k] # or whatever.
Это было бы намного быстрее, чем при использовании cmp
функция.
Вы не можете сортировать dict
в Python как dict
тип по своей природе неупорядочен. Что вы можете сделать, это отсортировать элементы, прежде чем использовать их с помощью sorted()
встроенная функция. Вам также понадобится вспомогательная функция, чтобы различать ваши числовые и строковые ключи:
def get_key(key):
try:
return int(key)
except ValueError:
return key
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 }
print sorted(a.items(), key=lambda t: get_key(t[0]))
Однако в Python 3.1 (и 2.7) collections
модуль содержит collections.OrderedDict
Тип, который может быть использован для достижения желаемого эффекта, как показано ниже:
def get_key(key):
try:
return int(key)
except ValueError:
return key
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 }
b = collections.OrderedDict(sorted(a.items(), key=lambda t: get_key(t[0])))
print(b)
9 лет назад я выложил рецепт, который начинается
Словари не могут быть отсортированы - отображение не имеет порядка!
и показывает, как получить отсортированные списки из ключей и значений dict.
С сегодняшним Python и вашими явно выраженными плюсами я бы предложил:
import sys
def asint(s):
try: return int(s), ''
except ValueError: return sys.maxint, s
sortedlist = [(k, a[k]) for k in sorted(a, key=asint)]
key=asint
это то, что говорит sorted
обрабатывать эти строковые ключи как целые числа для целей сортировки, например, '2'
сортирует между '1'
а также '12'
вместо того, чтобы следовать за ними обоими - это то, что вам, по-видимому, требуется, а также иметь все нецифровые ключи для сортировки после всех многозначных. Если вам также нужно иметь дело с цепочками из всех цифр, которые выражают целые числа больше sys.maxint, это немного сложнее, но все же выполнимо:
class Infinity(object):
def __cmp__(self, other): return 0 if self is other else 1
infinite = Infinity()
def asint(s):
try: return int(s), ''
except ValueError: return infinite, s
В целом, вы можете получить лучшие ответы быстрее, если будете более точно указывать свои точные требования;-).
Словари неупорядочены. Вы не можете сортировать, как вы показываете, потому что результат a
это диктат, а у диктов нет порядка.
Если вы хотите, скажем, список ключей в отсортированном порядке, вы можете использовать код как
>>> def my_key(dict_key):
... try:
... return int(dict_key)
... except ValueError:
... return dict_key
...
>>> sorted(a, key=my_key)
['1', '6', '67', '88', '100', 'test']
Это опирается на глупое поведение Python, что экземпляры str
всегда больше, чем случаи int
, (Поведение исправлено в Python 3.) В оптимальной схеме ключи вашего dict будут такими вещами, которые вы могли бы разумно сравнить, и вы бы не смешивали строки, представляющие числа, со строками, представляющими слова.
Если вы хотите хранить ключи в всегда отсортированном порядке, вы можете использовать bisect
модуль или реализовать отображение, которое опирается на древовидную структуру данных. bisect
модуль не принимает key
аргумент, как сортировка, потому что это было бы потенциально неэффективно; вы бы использовали шаблон decorate – use – undecorate, если бы выбрали bisect
сохраняя отсортированный список, который зависит от результата ключевой функции.
Если вы установите мой пакет blist, он включает в себя sorteddict
тип. Тогда вы могли бы просто:
from blist import sorteddict
def my_key(dict_key):
try:
return int(dict_key)
except ValueError:
return dict_key
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 }
print sorteddict(my_key, **a).keys()
Выход:
['1', '6', '67', '88', '100', 'test']
вы также можете сделать следующее:
sorted_keys = sorted(list(a.keys()), key = lambda x: (len(x),x))
sorted_dict = {k:a[k] for k in sorted_keys}
Самая важная часть - это
key = lambda x: (len(x),x)
который я взял отсюда