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

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

Ответы:


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

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


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синтаксис легче читать.


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'}

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.