Эффективный способ создать список или добавить его, если он уже существует? - PullRequest
39 голосов
/ 12 января 2010

Я прохожу целую кучу кортежей с соотношением «многие ко многим» и хочу составить словарь, в котором у каждого b of (a, b) есть список всех a, соответствующих b , Кажется неловким проверять список по ключу b в словаре, затем искать a, затем добавлять a, если его там еще нет, каждый раз в цикле переваривания кортежей; но я еще не нашел лучшего способа. Один существует? Есть ли другой способ сделать это намного красивее?

Ответы [ 8 ]

55 голосов
/ 12 января 2010

См. документы для setdefault() метода:

setdefault (клавиша [, по умолчанию])
Если ключ в словаре вернуть его значение. Если нет, введите ключ со значением по умолчанию и вернуть по умолчанию. дефолт по умолчанию Нет.

Вы можете использовать это как один вызов, который получит b, если он существует, или установить b в пустой список, если он еще не существует - и в любом случае вернуть b:

>>> key = 'b'
>>> val = 'a'
>>> print d
{}
>>> d.setdefault(key, []).append(val)
>>> print d
{'b': ['a']}
>>> d.setdefault(key, []).append('zee')
>>> print d
{'b': ['a', 'zee']}

Объедините это с простой проверкой «не в», и вы сделали то, что вам нужно, в трех строках:

>>> b = d.setdefault('b', [])
>>> if val not in b:
...   b.append(val)
... 
>>> print d
{'b': ['a', 'zee', 'c']}
17 голосов
/ 12 января 2010

Если вы действительно не привязаны к спискам, defaultdict и set довольно удобны.

import collections
d = collections.defaultdict(set)
for a, b in mappings:
    d[b].add(a)

Если вы действительно хотите списки вместо наборов, вы можете добавить к этому

for k, v in d.iteritems():
    d[k] = list(v)

И если вы действительно хотите диктовать вместо дефолта, вы можете сказать

d = dict(d)

Я, правда, не вижу причин, по которым вы бы захотели.

4 голосов
/ 12 января 2010

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

your_dict = defaultdict(list)
for (a,b) in your_list:
    your_dict[b].append(a)
3 голосов
/ 12 января 2010

Вместо использования if, AFAIK, более pythonic вместо использования блока try.

your_list=[('a',1),('a',3),('b',1),('f',1),('a',2),('z',1)]

your_dict={}
for (a,b) in your_list:
    try:
        your_dict[b].append(a)
    except KeyError:
        your_dict[b]=[a]

print your_dict
3 голосов
/ 12 января 2010

вы можете отсортировать свои кортежи O (n log n), а затем создать свой словарь O (n)

или более простое O (n), но может вызвать большую нагрузку на память в случае множества кортежей:

your_dict = {}
for (a,b) in your_list:
    if b in your_dict:
        your_dict[b].append(a)
    else:
        your_dict[b]=[a]

Хм, это почти так же, как вы описали. Что неловкого в этом?

Вы также можете рассмотреть возможность использования базы данных sql для грязной работы.

0 голосов
/ 30 января 2018

Есть еще один способ, который довольно эффективен (хотя, возможно, не так эффективен, как наборы) и прост. На практике это похоже на defaultdict, но не требует дополнительного импорта. Предполагается, что у вас есть dict с пустыми (None) ключами, это означает, что вы также где-то создаете ключи dict Вы можете сделать это с помощью метода dict.fromkeys, и этот метод также позволяет установить значение по умолчанию для всех клавиш.

keylist = ['key1', 'key2']
result = dict.fromkeys(keylist, [])

, где result будет: {'key1': [], 'key2': []}

Тогда вы можете сделать свой цикл и использовать result['key1'].append(..) напрямую

0 голосов
/ 18 июля 2017

Dict get метод? Возвращает значение my_dict[some_key], если some_key находится в словаре, а если нет - возвращает некоторое значение по умолчанию ([] в приведенном ниже примере):

my_dict[some_key] = my_dict.get(some_key, []).append(something_else)
0 голосов
/ 12 января 2010

Я не уверен, как вы выйдете из теста ключей, но как только пара ключей / значений будет инициализирована, это легко

d = {}
if 'b' not in d:
  d['b'] = set()
d['b'].add('a')

Набор гарантирует, что в коллекции будет только 1 из 'a'. Вы должны выполнить начальную проверку 'b', чтобы убедиться, что ключ / значение существуют.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...