Что является более быстрым способом объединения значений этой структуры Python в один словарь? - PullRequest
3 голосов
/ 12 марта 2010

Я изменил порядок создания словаря слияния (all_classes) ниже, но мне интересно, может ли он быть более эффективным.

У меня есть словарь словарей, например:

groups_and_classes = {'group_1': {'class_A': [1, 2, 3],
                                  'class_B': [1, 3, 5, 7], 
                                  'class_c': [1, 2], # ...many more items like this
                                 },
                      'group_2': {'class_A': [11, 12, 13],
                                  'class_C': [5, 6, 7, 8, 9]
                                 }, # ...and many more items like this
                     }

Функция создает новый объект из groups_and_classes следующим образом (часто вызывается функция для его создания):

all_classes = {'class_A': [1, 2, 3, 11, 12, 13],
               'class_B': [1, 3, 5, 7, 9],
               'class_C': [1, 2, 5, 6, 7, 8, 9]
              }

Прямо сейчас есть цикл, который делает это:

all_classes = {}
for group in groups_and_classes.values():
    for c, vals in group.iteritems():
        for v in vals:
            if all_classes.has_key(c):
                if v not in all_classes[c]:
                    all_classes[c].append(v)
            else:
                all_classes[c] = [v]

Пока что я изменил код для использования set вместо list, поскольку порядок списка не имеет значения и значения должны быть уникальными:

all_classes = {}
for group in groups_and_classes.values():
    for c, vals in group.iteritems():
        try:
            all_classes[c].update(set(vals))
        except KeyError:
            all_classes[c] = set(vals)

Это немного лучше, и мне не нужно было преобразовывать наборы в списки из-за того, как all_classes используется в коде.

Вопрос : Есть ли более эффективный способ создания all_classes (кроме создания его в то же время, когда создается groups_and_classes, и изменение везде, где эта функция вызывается)?

Ответы [ 3 ]

4 голосов
/ 12 марта 2010

Вот краткость для краткости, хотя я не уверен в производительности:

from collections import defaultdict
all_classes = defaultdict(set)
for group in groups_and_classes.values():
    for c, vals in group.iteritems():
        all_classes[c].update(set(vals))

Defaultdicts не совсем лучшая вещь после нарезанного хлеба, но они довольно крутые :)

2 голосов
/ 12 марта 2010

Объединение словарей списков в Python .

def merge_dols(dol1, dol2):
    result = dict(dol1, **dol2)
    result.update((k, dol1[k] + dol2[k]) for k in set(dol1).intersection(dol2))
    return result

g1 = groups_and_classes['group_1']
g2 = groups_and_classes['group_2']

all_classes = merge_dols(g1,g2)

OR

all_classes = reduce(merge_dols,groups_and_classes.values())

- скопировано с Алекс Мартелли

Если у вас более двух групп, вы можете использовать itertools.reduce

all_classes = reduce(merge_dols,groups_and_classes.values())
2 голосов
/ 12 марта 2010

Одна вещь, которая может немного улучшить ситуацию, - это избежать избыточного преобразования в набор и просто использовать:

all_classes[c].update(vals)

update на самом деле может принимать произвольную итерацию, поскольку она, по сути, просто повторяет и добавляет, так что вы можете избежать дополнительного шага преобразования.

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