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

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

{
  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,]

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

Ответ 1

Вы можете использовать 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'])]

Ответ 2

Вы можете создать его со списком, подобным этому:

>>> 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])]

Ответ 3

Используйте 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).

Ответ 4

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

if d.has_key(scope_item):

с:

if scope_item in d:

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

Ответ 5

Лично я просто использую 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'}

Ответ 6

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

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

print(d)
{'1': [1, ], '2':[2, ]}