Python диктует, как создать ключ или добавить элемент к ключу?

161

У меня есть пустой словарь. Название:dict_x это ключи, значения которых являются списками.

Из отдельной итерации я получаю ключ (ex:) key_123и элемент (кортеж) для помещения в список dict_xзначений key_123.

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

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

Мой код состоит из этого:

Получить ключ и значение.

Смотрите , если НЕ ключ существует в dict_x.

и если не создать его: dict_x[key] == []

После этого: dict_x[key].append(value)

Это способ сделать это? Должен ли я использовать try/exceptблоки?

Фил
источник

Ответы:

254

Используйте dict.setdefault():

dic.setdefault(key,[]).append(value)

help (dict.setdefault) :

    setdefault(...)
        D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
Ашвини Чаудхари
источник
4
Раньше я делал это, dict_x[key] = [some_value] if not dict_x.has_key(key) else dict_x[key] + [some_value]но этот ответ предлагает гораздо лучший способ. На самом деле это становится set()аргументом и позволяет вам использовать add()метод ...
fatih_dur
66

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

Использование collections.defaultdict:

import collections
dict_x = collections.defaultdict(list)

...

dict_x[key].append(value)

Плюсы: вероятно, лучшая производительность. Минусы: Недоступно в Python 2.4.x.

Использование dict().setdefault():

dict_x = {}

...

dict_x.setdefault(key, []).append(value)

Минусы: неэффективное создание неиспользованных list()с.

Использование try ... except:

dict_x = {}

...

try:
    values = dict_x[key]
except KeyError:
    values = dict_x[key] = []
values.append(value)

Или:

try:
    dict_x[key].append(value)
except KeyError:
    dict_x[key] = [value]
antak
источник
Здравствуйте, почему вы думаете .setdefault создает ненужные словари?
Фил
2
Я не думаю, что .setdefault()создает ненужные словари. Я думаю, что я создаю ненужные lists (то есть []) во втором аргументе, .setdefault()который никогда не используется, если он keyуже существует. Я мог бы использовать dict.setdefault()(для эффективного хеширования ключей) и использовать переменную для повторного использования неиспользуемых lists, но это добавляет еще несколько строк кода.
антак
1
IIRC, в Python пустой список в равенстве считается константой на уровне байт-кода, но это требует некоторого подтверждения гуру байт-кода (или просто используйте модуль disas).
Габорист
Использование .setdefaultсоздает обычную, dictгде поиск по отсутствующим ключам приведет к тому, что некоторое KeyErrorвремя collections.defaultdict(list)создаст dictпоиск по отсутствующим ключам, которая вставит пустую list- я думаю, вы должны выбрать, основываясь на том, какое поведение вы хотите
Chris_Rands
Я попробовал что-то похожее на collection.defaultdict в своем собственном коде, и у него были неожиданные побочные эффекты. Например, рассмотрим следующий обмен IDLE: >>> list_dict = defaultdict (список) >>> len (list_dict) 0 >>> len (list_dict [0]) 0 >>> len (list_dict) 1 Похоже, что когда Python вызывает значение по умолчанию добавляет ключ к словарю без активной его установки, что приведет к созданию большого количества пустых списков, если по умолчанию используется много. Я собираюсь свернуть мои собственные функции-обертки для словаря, неэффективные, но, надеюсь, более предсказуемые.
RDBury
26

Вы можете использовать defaultdict для этого.

from collections import defaultdict
d = defaultdict(list)
d['key'].append('mykey')

Это немного эффективнее, чем setdefaultкогда вы не создаете новые списки, которые не используете. Каждый вызов setdefaultсоздает новый список, даже если элемент уже существует в словаре.

Натан Вильяэскуса
источник
14

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

Пример из документа:

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
    d[k].append(v)
iMom0
источник
0
dictionary['key'] = dictionary.get('key', []) + list_to_append
Томас Силва Эбенспергер
источник
1
Вы должны объяснить (очень незначительное) преимущество, которое это имеет при наличии определенных исключений; как просто код, не понятно, зачем нужен дополнительный ответ.
Дэвис Херринг
Привет, просто альтернатива без дополнительного импорта. Это можно сделать с помощью оператора if. Я просто предлагаю альтернативу, использующую силу .get () вместо использования dict [].
Томас Сильва Эбенспергер
В двух верхних ответах упоминаются два разных способа без импорта (хотя и нет dict.get).
Дэвис Херринг