как назначить список значений ключу с помощью OrderedDict в python

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

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

from collections import defaultdict

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
dic = defaultdict(list)

i=0

for key in keys:
    dic[key].append(vals1[i])
    dic[key].append(vals2[i])

    i += 1

print dic

Я получаю следующий результат

defaultdict(<type 'list'>, {'pri': ['primary', 'S2'], 'ani': ['anim', 'S3'], 'blk': ['blocking', 'S1']})

здесь я потерял порядок вставки.

Я знаю, что объект defaultdict в Python неупорядочены по определению.

и я знаю, что нужно использовать OrderedDict если вам нужно порядок, в котором были вставлены значения (он доступен в Python 2.7 и 3.x)

так изменил мой код, как показано ниже

снизу кода я мог бы получить то, что мне нужно.

from collections import defaultdict,OrderedDict

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
dic = OrderedDict(defaultdict(list))

i=0

for key in keys:
    dic[key].append(vals1[i])
    dic[key].append(vals2[i])

    i += 1

print dic

и теперь я получаю следующую ошибку

Traceback (most recent call last):
  File "Dict.py", line 18, in <module>
    dic[key].append(vals1[i])
KeyError: 'blk' 

может кто-нибудь сказать мне, как получить то, что я пытаюсь.

3 ответов


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

from collections import OrderedDict

class DefaultListOrderedDict(OrderedDict):
    def __missing__(self,k):
        self[k] = []
        return self[k]

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
dic = DefaultListOrderedDict()
for i,key in enumerate(keys):
    dic[key].append(vals1[i])
    dic[key].append(vals2[i])

print dic

это будет вести себя больше как defaultdict чем другие решения, но он сохранит порядок, и это действительно не так много кода :). Наконец, вы даже можете переопределить __init__ чтобы позволить пользователю пройти любую "фабрику", которую они хотели (а не жесткое кодирование list). Я оставлю это в качестве упражнения для заинтересованный читатель. Python такой классный.


проблема с переносом OrderedDict вокруг defaultdict(list) это то, что он оценивается таким образом:

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

это не сочетает в себе их поведение, как вы хотели.

стандартная идиома, которую я видел, это dict.setdefault метод.

from collections import OrderedDict

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
dic = OrderedDict()

i=0

for key in keys:
    dic.setdefault(key, []).append(vals1[i])
    dic.setdefault(key, []).append(vals2[i])

    i += 1

print dic

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

Я бы использовал этот подход, хотя:

from collections import OrderedDict
dic = OrderedDict(zip(keys, zip(vals1, vals2)))
print dic

попробуйте это:

from collections import OrderedDict

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
print OrderedDict(zip(keys, zip(vals1, vals2)))