Самый эффективный способ добавить новые ключи или добавить старые ключи в словарь во время итерации в Python? - PullRequest
3 голосов
/ 12 октября 2009

Вот типичная ситуация при компиляции данных в словарях из разных источников:

Скажем, у вас есть словарь, в котором хранятся списки вещей, например, которые мне нравятся:

likes = {
    'colors': ['blue','red','purple'],
    'foods': ['apples', 'oranges']
}

и второй словарь с некоторыми значениями в нем:

favorites = {
    'colors':'yellow',
    'desserts':'ice cream'
}

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

Есть несколько способов сделать это:

for key in favorites:
    if key in likes:
        likes[key].append(favorites[key])
    else:
        likes[key] = list(favorites[key])

или

for key in favorites:
    try:
        likes[key].append(favorites[key])
    except KeyError:
        likes[key] = list(favorites[key])

И многое другое ...

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

Ответы [ 5 ]

5 голосов
/ 12 октября 2009

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

>>> import collections
>>> mydict = collections.defaultdict(list)

Таким образом, вызов .append(...) всегда будет успешным, потому что в случае несуществующего ключа append будет вызываться в новом пустом списке.

Вы можете создать экземпляр defaultdict с ранее созданным списком, в случае, если вы получите диктовку likes из другого источника, например:

>>> mydict = collections.defaultdict(list, likes)

Обратите внимание, что использование list в качестве атрибута default_factory для defaultdict также обсуждается в качестве примера в документации .

3 голосов
/ 12 октября 2009

Использовать collection.defaultdict:

import collections

likes = collections.defaultdict(list)

for key, value in favorites.items():
    likes[key].append(value)

defaultdict принимает один аргумент, фабрику для создания значений для неизвестных ключей по требованию. list - это такая функция, она создает пустые списки.

И повторение .items () избавит вас от использования ключа для получения значения.

2 голосов
/ 12 октября 2009

Кроме defaultdict, обычный dict предлагает одну возможность (это может выглядеть немного странно): dict.setdefault(k[, d]):

for key, val in favorites.iteritems():
    likes.setdefault(key, []).append(val)

Спасибо за +20 в респ. Я прошел с 1989 по 2009 год за 30 секунд. Давайте вспомним, что прошло 20 лет с тех пор, как Стена упала в Европе ..

1 голос
/ 28 сентября 2010

Все ответы defaultdict, но я не уверен, что это лучший способ сделать это. Выдавать defaultdict коду, который ожидает, что диктат может быть плохим. (См .: Как сделать дефолт безопасным для неопытных клиентов? ) Я лично разрываюсь по этому вопросу. (На самом деле я нашел этот вопрос в поисках ответа на вопрос «что лучше, dict.get() или defaultdict»). Кто-то в другой ветке сказал, что вам не нужен defaultdict, если вы не хотите, чтобы это поведение все время, и это может быть правдой. Возможно, использование defaultdict для удобства - неправильный путь. Я думаю, что здесь необходимо сопоставить две потребности:

«Мне нужен дикт, чьи значения по умолчанию - пустые списки». для которого defaultdict(list) является правильным решением.

и

«Я хочу добавить в список по этому ключу, если он существует, и создать список, если он не существует». на что my_dict.get('foo', []) с append() является ответом.

Что вы, ребята, думаете?

1 голос
/ 12 октября 2009
>>> from collections import defaultdict
>>> d = defaultdict(list, likes)
>>> d
defaultdict(<class 'list'>, {'colors': ['blue', 'red', 'purple'], 'foods': ['apples', 'oranges']})
>>> for i, j in favorites.items():
    d[i].append(j)

>>> d
defaultdict(<class 'list'>, {'desserts': ['ice cream'], 'colors': ['blue', 'red', 'purple', 'yellow'], 'foods': ['apples', 'oranges']})
...