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

214

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

{
  1: ['1'],
  2: ['1','2'],
  3: ['2']
}

Если я сделаю:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d[j].append(i)

Я получаю KeyError, потому что d [...] не список. В этом случае я могу добавить следующий код после присваивания a для инициализации словаря.

for x in range(1, 4):
    d[x] = list()

Есть лучший способ сделать это? Допустим, я не знаю ключей, которые мне понадобятся, пока не попаду во второй forцикл. Например:

class relation:
    scope_list = list()
...
d = dict()
for relation in relation_list:
    for scope_item in relation.scope_list:
        d[scope_item].append(relation)

Альтернативой тогда будет замена

d[scope_item].append(relation)

с участием

if d.has_key(scope_item):
    d[scope_item].append(relation)
else:
    d[scope_item] = [relation,]

Каков наилучший способ справиться с этим? В идеале, добавление будет "просто работать". Есть ли способ выразить, что я хочу словарь пустых списков, даже если я не знаю каждый ключ при первом создании списка?

user118662
источник

Ответы:

279

Вы можете использовать defaultdict :

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> a = ['1', '2']
>>> for i in a:
...   for j in range(int(i), int(i) + 2):
...     d[j].append(i)
...
>>> d
defaultdict(<type 'list'>, {1: ['1'], 2: ['1', '2'], 3: ['2']})
>>> d.items()
[(1, ['1']), (2, ['1', '2']), (3, ['2'])]
mechanical_meat
источник
1
Другие словари под collectionsмодулем также работают, например, таким образом collections.OrderedDict.
txsaw1
2
Ой. Это круто. И вам не нужно инициализировать '= []'. Хорошая вещь!
Уилмер Э. Энао
1
NameError: name 'a' is not defined
С Андрей
52

Вы можете построить это с помощью понимания списка следующим образом:

>>> dict((i, range(int(i), int(i) + 2)) for i in ['1', '2'])
{'1': [1, 2], '2': [2, 3]}

А для второй части вашего вопроса используйте defaultdict

>>> from collections import defaultdict
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
        d[k].append(v)

>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Надя Алрамли
источник
32

Вы можете использовать setdefault:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d.setdefault(j, []).append(i)

print d  # prints {1: ['1'], 2: ['1', '2'], 3: ['2']}

Довольно странно названная setdefaultфункция говорит: «Получите значение с помощью этого ключа, или, если этого ключа нет, добавьте это значение и затем верните его».

Как правильно отметили другие, defaultdictэто лучший и более современный выбор. setdefaultвсе еще полезен в более старых версиях Python (до 2.5).

RichieHindle
источник
2
Это работает, но обычно предпочтительнее использовать defaultdict, когда он доступен.
Дэвид З
@ Дэвид, да, setdefault был не самым ярким дизайном, извини - вряд ли это лучший выбор. Я думаю, что мы (коммиттеры Python) восстановили нашу коллективную репутацию с использованием collection.defaultdict ;-).
Алекс Мартелли
@DavidZ, setdefault отличается от defaultdict, так как он более гибкий: в противном случае, как вы определяете разные значения по умолчанию для разных ключей словаря?
Алекс Гидан
@AlexGidan Это правда, но не особенно относится к этому вопросу.
Дэвид З
Этот ответ также полезен, когда вам нужен OrderedDict и значение по умолчанию.
nimcap
2

На ваш вопрос уже дан ответ, но IIRC вы можете заменить на такие строки:

if d.has_key(scope_item):

с участием:

if scope_item in d:

То есть dссылки d.keys()в этой конструкции. Иногда defaultdictэто не лучший вариант (например, если вы хотите выполнить несколько строк кода после elseсвязанного с вышеупомянутым if), и я считаю, что inсинтаксис легче читать.

spiffyman
источник
2

Лично я просто использую JSON для преобразования вещей в строки и обратно. Строки я понимаю.

import json
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
mydict = {}
hash = json.dumps(s)
mydict[hash] = "whatever"
print mydict
#{'[["yellow", 1], ["blue", 2], ["yellow", 3], ["blue", 4], ["red", 1]]': 'whatever'}
Джон Ктехик
источник
1

Простой способ это:

a = [1,2]
d = {}
for i in a:
  d[i]=[i, ]

print(d)
{'1': [1, ], '2':[2, ]}
Хеннинг Ли
источник