Как сохранить ключи / значения в том же порядке, как объявлено?


320

У меня есть словарь, который я объявил в определенном порядке, и я хочу постоянно держать его в этом порядке. Ключи / значения не могут быть сохранены в порядке, основанном на их значении, я просто хочу их в том порядке, в котором я их объявил.

Так что, если у меня есть словарь:

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}

Это не в том порядке, если я его просматриваю или перебираю, есть ли способ убедиться, что Python сохранит явный порядок, в котором я объявил ключи / значения?

Ответы:


229

Начиная с Python 3.6, стандартный dictтип поддерживает порядок вставки по умолчанию.

определяющий

d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}

приведет к появлению словаря с ключами в порядке, указанном в исходном коде.

Это было достигнуто путем использования простого массива с целыми числами для разреженной хеш-таблицы, где эти целые числа индексируют в другой массив, в котором хранятся пары ключ-значение (плюс вычисленный хеш). Этот последний массив просто хранит элементы в порядке вставки, и вся комбинация фактически использует меньше памяти, чем реализация, используемая в Python 3.5 и ранее. Посмотрите оригинальное сообщение идеи Раймондом Хеттингером для деталей.

В 3.6 это все еще считалось деталью реализации; см в Что нового в Python 3.6 документации :

Сохраняющий порядок аспект этой новой реализации считается деталью реализации, и на него не следует полагаться (это может измениться в будущем, но желательно иметь эту новую реализацию dict в языке в течение нескольких выпусков, прежде чем изменять спецификацию языка. предписывать семантику сохранения порядка для всех текущих и будущих реализаций Python, что также помогает сохранить обратную совместимость со старыми версиями языка, где все еще действует случайный порядок итераций, например, Python 3.5).

Python 3.7 переводит эту деталь реализации в спецификацию языка , поэтому теперь обязательно dictсохранять порядок во всех реализациях Python, совместимых с этой версией или более новой. Смотрите заявление BDFL .

Вы все еще можете использовать collections.OrderedDict()класс в некоторых случаях, так как он предлагает некоторые дополнительные функции поверх стандартного dictтипа. Например, быть обратимым (это распространяется на объекты вида ) и поддерживать переупорядочение (с помощью move_to_end()метода ).


К сожалению, это не относится к созданию словаря . Словари, указанные как в примере в коде, не гарантируют того же порядка. Это означает, что вам нужно создать пустой dict и вручную вставить каждый элемент, если вы хотите контролировать порядок.
naught101

8
@ naught101: нет, это действительно применяется к созданию Dict. В Python 3.7 и более поздних версиях использование указателя разметки, как показано в вопросе , гарантирует перечисление этих ключей по порядку . Пары ключ-значение в том виде, в котором они записаны, вставляются слева направо, потому что спецификация языка гарантирует, что : если задана разделенная запятыми последовательность пар ключ / опорная точка, они оцениваются слева направо для определения записей словаря . dict()Документация включает в себя даже пример.
Мартин Питерс

175
from collections import OrderedDict
OrderedDict((word, True) for word in words)

содержит

OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])

Если значения True(или любой другой неизменный объект), вы также можете использовать:

OrderedDict.fromkeys(words, True)

2
Стоит отметить, конечно, что «неизменяемая» часть не является жестким и быстрым правилом, которое Python будет применять - это «только» хорошая идея.
lvc

11
Имейте в OrderedDict(FUTURE=[], TODAY=[], PAST=[])виду, что такие решения, как: не будут работать, когда упомянуто о подходе: OrderedDict([('FUTURE', []), ('TODAY', []), ('PAST', [])])будут поддерживать порядок.
andilabs

2
@andi У меня возникла другая проблема: при использовании jsonify OrderedDict теряет свой порядок при генерации данных json. В любом случае, чтобы решить эту проблему?
Тян

github.com/pallets/flask/issues/974 это можно использовать для решения проблемы ..
Тян

5
В Python3.7 теперь по умолчанию установлен dict. mail.python.org/pipermail/python-dev/2017-De
December/

167

Вместо объяснения теоретической части приведу простой пример.

>>> from collections import OrderedDict
>>> my_dictionary=OrderedDict()
>>> my_dictionary['foo']=3
>>> my_dictionary['aol']=1
>>> my_dictionary
OrderedDict([('foo', 3), ('aol', 1)])
>>> dict(my_dictionary)
{'foo': 3, 'aol': 1}

16
Есть ли способ массового присвоения OrderedDict как тип Dict?
Тян

2
OrderedDictдействительно решает проблему, но ... в этом конкретном примере вы получите точно такой же результат, используя стандартный словарь
Tonechas

2
@Tonechas: я только что попробовал пример со стандартным словарем, и получил, {'aol': 1, 'foo': 3}так что я думаю, что это хороший иллюстративный пример.
twasbrillig

4
Урок для всех: было обнаружено (я думаю, что в версии 2.4), что предсказуемое хеширование Python может привести к уязвимостям безопасности , поэтому теперь нет гарантии, что даже два разных прогона одного и того же кода приведут к одному и тому же порядку в стандартном ДИКТ.
Holdenweb

1
@tyan можно вызвать OrderedDict.update()с итератора парами , содержащими ключ-значение: d1.upate([(key1, val1), (key2, val2)]).
Рууд Альтхуйзен,

37

Обратите внимание, что этот ответ относится к версиям Python до Python3.7. CPython 3.6 поддерживает порядок вставки в большинстве случаев как деталь реализации. Начиная с Python3.7, было объявлено, что реализации ДОЛЖНЫ поддерживать порядок вставки, чтобы быть совместимыми.


Словари Python неупорядочены. Если вы хотите заказать словарь, попробуйте collection.OrderedDict .

Обратите внимание, что OrderedDict был введен в стандартную библиотеку в python 2.7. Если у вас более старая версия python, вы можете найти рецепты заказанных словарей в ActiveState .


см. пост @ martijn выше. Начиная с версии Python 3.6, dict поддерживает порядок вставки.
TPK

13

Словари будут использовать порядок, который делает поиск эффективным, и вы не можете изменить это,

Вы можете просто использовать список объектов (кортеж из 2 элементов в простом случае или даже класс) и добавлять элементы в конец. Затем вы можете использовать линейный поиск, чтобы найти элементы в нем.

В качестве альтернативы вы можете создать или использовать другую структуру данных, созданную с целью поддержания порядка.


Словари будут использовать порядок, который делает поиск эффективным Наконец, кто-то указал на это.
Шарет

7

Я наткнулся на этот пост, пытаясь выяснить, как заставить OrderedDict работать. PyDev для Eclipse не смог найти OrderedDict вообще, поэтому я решил сделать кортеж из значений моего словаря, как я хотел бы, чтобы они были упорядочены. Когда мне нужно было вывести свой список, я просто перебирал значения кортежа и вставлял повторяющийся «ключ» из кортежа в словарь, чтобы получить мои значения в том порядке, в котором они мне нужны.

пример:

test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
test_tuple = ( 'val1', 'val2', 'val3', 'val4')
for key in test_tuple: print(test_dict[key])

Это немного громоздко, но мне не хватает времени, и это обходной путь, который я нашел.

примечание: подход со списком списков, который предложил кто-то другой, на самом деле не имеет смысла для меня, потому что списки упорядочены и проиндексированы (и также имеют другую структуру, чем словари).


Отличное решение. Я буду использовать его для записи JSON в файл, всегда в том же порядке.
Hrvoje T

6

Вы не можете действительно делать то, что вы хотите со словарем. У вас уже есть словарь d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}. Я обнаружил, что не было никакого способа поддерживать порядок, когда он уже создан. Вместо этого я создал файл json с объектом:

{"ac":33,"gw":20,"ap":102,"za":321,"bs":10}

Я использовал:

r = json.load(open('file.json'), object_pairs_hook=OrderedDict)

затем использовали:

print json.dumps(r)

проверять.


1
Так почему бы не начать с OrderedDict из списка? Файл JSON здесь ничего не добавляет.
Мартин Питерс

Да, список более полезен для поддержания порядка, но ответ был на вопрос о заказе словарей. Просто дайте людям знать об ограничениях использования словаря и дайте им возможное решение, если им по какой-то причине нужно использовать словарь.
nealous3

1
Но эта часть уже охвачена гораздо более ранними ответами, начиная с 2012 года.
Мартейн Питерс

3
from collections import OrderedDict
list1 = ['k1', 'k2']
list2 = ['v1', 'v2']
new_ordered_dict = OrderedDict(zip(list1, list2))
print new_ordered_dict
# OrderedDict([('k1', 'v1'), ('k2', 'v2')])

главная проблема, которая больше не диктат, это список кортежей
Олег

2

Другой альтернативой является использование Pandas, dataframeпоскольку он гарантирует порядок и индексные позиции элементов в структуре, похожей на диктовку.


1

Как правило, вы можете создать класс , который ведет себя как словарь, главным образом , быть реализации методов __contains__, __getitem__, __delitem__, __setitem__и некоторые другие. Этот класс может иметь любое поведение, которое вам нравится, например, выделение отсортированного итератора для ключей ...


1

если вы хотите иметь словарь в определенном порядке, вы также можете создать список списков, где первый элемент будет ключом, а второй элемент будет значением и будет выглядеть следующим образом

>>> list =[[1,2],[2,3]]
>>> for i in list:
...     print i[0]
...     print i[1]

1
2
2
3

7
Это не «словарь», потому что вы не можете искать элементы по их ключу, не просматривая всю коллекцию (занимая O (n) время).
BHSPitMonkey

1
Да, это не словарь, но, в зависимости от ситуации, он может дать правильное решение проблемы оригинального плаката.
SunSparc

он не сказал точно, как мы хотели, просто хотят иметь возможность их заказать =), как всегда, есть много способов сделать одну вещь.
Пелос

1

У меня была похожая проблема при разработке проекта Django. Я не мог использовать OrderedDict, потому что у меня была старая версия python, поэтому решение было использовать класс SortedDict Django:

https://code.djangoproject.com/wiki/SortedDict

например,

from django.utils.datastructures import SortedDict
d2 = SortedDict()
d2['b'] = 1
d2['a'] = 2
d2['c'] = 3

Примечание. Этот ответ был получен в 2011 году. Если у вас есть доступ к Python версии 2.7 или выше, то вы должны иметь доступ к стандарту collections.OrderedDict, который сейчас приведен , и многие примеры были предоставлены другими в этой теме.


0

Вы можете сделать то же самое, что я сделал для словаря.

Создайте список и пустой словарь:

dictionary_items = {}
fields = [['Name', 'Himanshu Kanojiya'], ['email id', 'hima@gmail.com']]
l = fields[0][0]
m = fields[0][1]
n = fields[1][0]
q = fields[1][1]
dictionary_items[l] = m
dictionary_items[n] = q
print dictionary_items
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.