Преобразование dict в OrderedDict

138

У меня возникли проблемы с использованием collections.OrderedDictкласса. Я использую Python 2.7 на Raspbian, дистрибутив Debian для Raspberry Pi. Я пытаюсь напечатать два словаря для сравнения (рядом) текстового приключения. Порядок необходимо точно сравнить. Что бы я ни старался, словари печатать в обычном неупорядоченном виде.

Вот что я получаю, когда делаю это на своем RPi:

import collections

ship = {"NAME": "Albatross",
         "HP":50,
         "BLASTERS":13,
         "THRUSTERS":18,
         "PRICE":250}

ship = collections.OrderedDict(ship)

print ship
# OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])

Очевидно, что что-то не так, потому что он печатает вызов функции и помещает ключи и группы значений во вложенный список ...

Вот что я получил, запустив нечто подобное на моем ПК:

import collections

Joe = {"Age": 28, "Race": "Latino", "Job": "Nurse"}
Bob = {"Age": 25, "Race": "White", "Job": "Mechanic", "Random": "stuff"}

#Just for clarity:
Joe = collections.OrderedDict(Joe)
Bob = collections.OrderedDict(Bob)

print Joe
# OrderedDict([('Age', 28), ('Race', 'Latino'), ('Job', 'Nurse')])
print Bob
# OrderedDict([('Age', 25), ('Race', 'White'), ('Job', 'Mechanic'), ('Random', 'stuff')])

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

Где я делаю свою ошибку? Это не должно быть связано с пи-версией Python, потому что это всего лишь версия для Linux.

pythonpiboy
источник
3
Примечание: OrderedDictсортируется по порядку вставки, а не по алфавитно-цифровому порядку клавиш.
el.pescado

Ответы:

214

Сначала вы создаете словарь , а затем передаете этот словарь в OrderedDict. Для версий Python <3.6 (*) к тому времени, когда вы это сделаете, порядок больше не будет правильным. dictпо своей сути не заказан.

Вместо этого передайте последовательность кортежей:

ship = [("NAME", "Albatross"),
        ("HP", 50),
        ("BLASTERS", 13),
        ("THRUSTERS", 18),
        ("PRICE", 250)]
ship = collections.OrderedDict(ship)

Когда вы печатаете, вы видите OrderedDictего представление , и оно совершенно правильно. OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])просто показывает вам, в воспроизводимом представлении, каково содержимое OrderedDict.


(*) : В реализации CPython 3.6 dictтип был обновлен, чтобы использовать внутреннюю структуру с более эффективным использованием памяти, которая имеет побочный эффект сохранения порядка вставки, и, следовательно, код, показанный в вопросе, работает без проблем. Начиная с Python 3.7, спецификация языка Python была обновлена, чтобы требовать, чтобы все реализации Python следовали этому поведению. Посмотрите этот другой мой ответ для деталей, а также почему вы все еще можете использовать OrderedDict()для определенных случаев.

Мартейн Питерс
источник
Итак, OrderedDict создаст словарь для меня? Кроме того, чтобы напечатать без воспроизводимого представления, я могу просто напечатать переменную, в которой используется OrderedDict? то есть: print ship ?? Спасибо :)
pythonpiboy
3
Вопрос: Как вы описали, OrderedDict составляет упорядоченный «список». Разве это не побеждает цель? Он создает просто список элементов, а не словарей с ключами и значениями ...
pythonpiboy
9
Тип действует как оба; отображение, которое сохраняет порядок. Чтобы создать один с заказом, нужно привести в порядок предметы . Поскольку стандартный dict (на чем-либо, кроме PyPI или Python 3.6+) не может этого сделать, вместо этого вы даете ему список кортежей. После того , как OrderedDictбудет создан он является словарем.
Мартин Питерс
4
Похоже, путаница заключается в том, что OrderedDict «применяет» порядок, а не просто сохраняет порядок. Я, конечно, предполагал, что он будет сортировать входные данные при создании - или что функция items () будет возвращать отсортированные элементы независимо от того, когда они были вставлены. Вместо этого он просто сохраняет все, что вы заказываете.
whiterook6
2
@ whiterook6: это не отсортированный словарь нет. Это упорядоченный словарь, словарь, который записывает порядок пар ключ-значение и позволяет вам переупорядочивать эти пары. Сравните это со списками, которые являются упорядоченными последовательностями .
Мартин Питерс
36

Если вы не можете отредактировать эту часть кода, где был определен ваш dict, вы все равно можете упорядочить его в любом месте любым удобным для вас способом, например так:

from collections import OrderedDict

order_of_keys = ["key1", "key2", "key3", "key4", "key5"]
list_of_tuples = [(key, your_dict[key]) for key in order_of_keys]
your_dict = OrderedDict(list_of_tuples)
Ян Розицки
источник
11

Большую часть времени мы обращаемся к OrderedDict, когда нам требовался нестандартный заказ, а не общий, такой как ASC и т. Д.

Вот предлагаемое решение:

import collections
ship = {"NAME": "Albatross",
         "HP":50,
         "BLASTERS":13,
         "THRUSTERS":18,
         "PRICE":250}

ship = collections.OrderedDict(ship)

print ship


new_dict = collections.OrderedDict()
new_dict["NAME"]=ship["NAME"]
new_dict["HP"]=ship["HP"]
new_dict["BLASTERS"]=ship["BLASTERS"]
new_dict["THRUSTERS"]=ship["THRUSTERS"]
new_dict["PRICE"]=ship["PRICE"]


print new_dict

Это будет вывод:

OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])
OrderedDict([('NAME', 'Albatross'), ('HP', 50), ('BLASTERS', 13), ('THRUSTERS', 18), ('PRICE', 250)])

Примечание . Новые отсортированные словари сохраняют порядок сортировки при удалении записей. Но когда добавляются новые ключи, ключи добавляются в конец, и сортировка не поддерживается. ( Официальный документ )

Абдул Маджид
источник
2

Используйте dict.items (); это может быть так просто, как показано ниже:

ship = collections.OrderedDict(ship.items())
Мохаммад-Али
источник