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

124

Как правильно инициализировать упорядоченный словарь (OD), чтобы он сохранял порядок исходных данных?

from collections import OrderedDict

# Obviously wrong because regular dict loses order
d = OrderedDict({'b':2, 'a':1}) 

# An OD is represented by a list of tuples, so would this work?
d = OrderedDict([('b',2), ('a', 1)])

# What about using a list comprehension, will 'd' preserve the order of 'l'
l = ['b', 'a', 'c', 'aa']
d = OrderedDict([(i,i) for i in l])

Вопрос:

  • Будет ли OrderedDictсохранен порядок списка кортежей, кортежа кортежей или кортежа списков или списка списков и т.д., переданных во время инициализации (2-й и 3-й примеры выше)?

  • Как можно проверить, OrderedDictдействительно ли поддерживается заказ? Поскольку a dictимеет непредсказуемый порядок, что, если мои тестовые векторы, к счастью, имеют тот же начальный порядок, что и непредсказуемый порядок dict? Например, если вместо того, чтобы d = OrderedDict({'b':2, 'a':1})писать d = OrderedDict({'a':1, 'b':2}), я могу ошибочно сделать вывод, что порядок сохраняется. В этом случае я обнаружил, что a dictупорядочен по алфавиту, но это может быть не всегда так. Какой надежный способ использовать контрпример для проверки того, сохраняет ли структура данных порядок или нет, кроме многократных попыток тестовых векторов, пока один из них не сломается?

PS Я просто оставлю это здесь для справки : «Конструктор OrderedDict и метод update () оба принимают аргументы ключевого слова, но их порядок теряется, потому что аргументы ключевого слова передачи семантики функции Python используют обычный неупорядоченный словарь»

PPS: Надеюсь, что в будущем OrderedDict также сохранит порядок kwargs (пример 1): http://bugs.python.org/issue16991

щелчок
источник
10
Какая-то ирония в том, что инициализация OrderedDict с (непустым) dict - неправильная вещь ... возможно, это должно привести к предупреждению, поскольку это, вероятно, нарушает намерения пользователя.
smci 03
3
После python3.6 OrderDict(b=2, a=1)это тоже правильный путь. См. PEP 468 .
IvanaGyro

Ответы:

90

OrderedDict сохранит любой порядок, к которому у него есть доступ. Единственный способ передать ему упорядоченные данные для инициализации - это передать список (или, в более общем смысле, итерацию) пар ключ-значение, как в ваших последних двух примерах. Как говорится в документации, на которую вы ссылаетесь, OrderedDict не имеет доступа к какому-либо порядку, когда вы передаете аргументы ключевого слова или аргумент dict, поскольку любой порядок там удаляется до того, как его увидит конструктор OrderedDict.

Обратите внимание, что использование списка в вашем последнем примере ничего не меняет. Нет разницы между OrderedDict([(i,i) for i in l])и OrderedDict([('b', 'b'), ('a', 'a'), ('c', 'c'), ('aa', 'aa')]). Понимание списка оценивается и создает список, который передается; OrderedDict ничего не знает о том, как он был создан.

BrenBarn
источник
74
# An OD is represented by a list of tuples, so would this work?
d = OrderedDict([('b', 2), ('a', 1)])

Да, это сработает. По определению список всегда упорядочен так, как он представлен. Это также относится к пониманию списка, список создается таким же образом, как и данные (т.е. источник из списка будет детерминированным, полученным из a setили dictне так много).

Как можно проверить, OrderedDictдействительно ли поддерживается порядок. Поскольку dict имеет непредсказуемый порядок, что, если мои тестовые векторы, к счастью, имеют тот же начальный порядок, что и непредсказуемый порядок dict ?. Например, если вместо того, чтобы d = OrderedDict({'b':2, 'a':1})писать d = OrderedDict({'a':1, 'b':2}), я могу ошибочно сделать вывод, что порядок сохраняется. В этом случае я обнаружил, что a dictнаходится в алфавитном порядке, но это может быть не всегда так. т.е. какой надежный способ использовать пример счетчика, чтобы проверить, сохраняет ли структура данных порядок или нет, за исключением многократных попыток тестовых векторов, пока один из них не сломается.

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

metatoaster
источник
О проверке порядка: как мне убедиться, что мой кортеж из двух кортежей БУДЕТ нарушать порядок dict, если он непредсказуем? Это общий вопрос о любой структуре данных, возможно, мне следует отделить его от этого вопроса.
щелкните
1
Вы не можете детерминированно сломать что-то недетерминированное по своей природе.
metatoaster
1
Итак, как правильно тестировать такие вещи? Вы просто продолжаете пытаться бесконечно? Порядок непредсказуем для программистов, но поскольку это хеш-карта, она следует «некоторому» алгоритму, и правильный тест должен попытаться противостоять этому?
нажмите
2
Смотрите __hash__. Конкретно о strтипе.
metatoaster
По определению список всегда упорядочен так, как он представлен. Это было для меня ключевым заявлением. Я решил просто использовать список из двух кортежей в качестве основного, OrderedDictчтобы у меня не было накладных расходов на преобразование списка в файл OrderedDict. Я просто перебираю элементы как список вместо словаря.
Боборт