Подтвердить что ты не робот

Python эквивалент zip для словарей

Если у меня есть эти два списка:

la = [1, 2, 3]
lb = [4, 5, 6]

Я могу перебирать их следующим образом:

for i in range(min(len(la), len(lb))):
    print la[i], lb[i]

Или больше pythonically

for a, b in zip(la, lb):
    print a, b

Что делать, если у меня есть два словаря?

da = {'a': 1, 'b': 2, 'c': 3}
db = {'a': 4, 'b': 5, 'c': 6}

Снова я могу выполнить итерацию вручную:

for key in set(da.keys()) & set(db.keys()):
    print key, da[key], db[key]

Есть ли встроенный метод, который позволяет мне выполнять итерацию следующим образом?

for key, value_a, value_b in common_entries(da, db):
    print key, value_a, value_b 
4b9b3361

Ответ 1

Нет встроенной функции или метода, которые могут это сделать. Однако вы можете легко определить свои собственные.

def common_entries(*dcts):
    for i in set(dcts[0]).intersection(*dcts[1:]):
        yield (i,) + tuple(d[i] for d in dcts)

Это основано на "ручном методе", который вы предоставляете, но, например, zip, может использоваться для любого количества словарей.

>>> da = {'a': 1, 'b': 2, 'c': 3}
>>> db = {'a': 4, 'b': 5, 'c': 6}
>>> list(common_entries(da, db))
[('c', 3, 6), ('b', 2, 5), ('a', 1, 4)]

Когда в качестве аргумента предоставляется только один словарь, он по существу возвращает dct.items().

>>> list(common_entries(da))
[('c', 3), ('b', 2), ('a', 1)]

Ответ 2

Возможно, вы захотите сделать пересечение, используя тип набора Python.

da = {'a': 1, 'b': 2, 'c': 3, 'e': 7}
db = {'a': 4, 'b': 5, 'c': 6, 'd': 9}

dc = set(da) & set(db)

for i in dc:
  print i,da[i],db[i]

Приветствия,

К.

Ответ 3

Если кто-то ищет обобщенное решение:

import operator
from functools import reduce


def zip_mappings(*mappings):
    keys_sets = map(set, mappings)
    common_keys = reduce(set.intersection, keys_sets)
    for key in common_keys:
        yield (key,) + tuple(map(operator.itemgetter(key), mappings))

или если вам нравится отделять ключ от значений и использовать синтаксис типа

for key, (values, ...) in zip_mappings(...):
    ...

мы можем заменить последнюю строку на

yield key, tuple(map(operator.itemgetter(key), mappings))

Испытания

from collections import Counter


counter = Counter('abra')
other_counter = Counter('kadabra')
last_counter = Counter('abbreviation')
for (character,
     frequency, other_frequency, last_frequency) in zip_mappings(counter,
                                                                 other_counter,
                                                                 last_counter):
    print('character "{}" has next frequencies: {}, {}, {}'
          .format(character,
                  frequency,
                  other_frequency,
                  last_frequency))

дает нам

character "a" has next frequencies: 2, 3, 2
character "r" has next frequencies: 1, 1, 1
character "b" has next frequencies: 1, 1, 2

(проверено на Python 2.7.12 и Python 3.5.2)

Ответ 4

Словарные представления уже установлены в Python 3. Вы можете удалить set():

for key in da.keys() & db.keys():
    print(key, da[key], db[key])

В Python 2:

for key in da.viewkeys() & db.viewkeys():
    print key, da[key], db[key]