Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python equivalent of zip for dictionaries

If I have these two lists:

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

I can iterate over them as follows:

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

Or more pythonically

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

What if I have two dictionaries?

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

Again, I can iterate manually:

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

Is there some builtin method that allows me to iterate as follows?

for key, value_a, value_b in common_entries(da, db):
    print key, value_a, value_b 
like image 477
Eric Avatar asked May 09 '13 09:05

Eric


People also ask

Can you zip dictionaries in Python?

Python's zip() function is defined as zip(*iterables) . The function takes in iterables as arguments and returns an iterator. This iterator generates a series of tuples containing elements from each iterable. zip() can accept any type of iterable, such as files, lists, tuples, dictionaries, sets, and so on.

What is zip () in Python?

Python zip() Function The zip() function returns a zip object, which is an iterator of tuples where the first item in each passed iterator is paired together, and then the second item in each passed iterator are paired together etc.

How do you zip multiple lists in Python?

To zip multiple lists, you can just do zip(list1, list2, list3) , etc.


4 Answers

There is no built-in function or method that can do this. However, you could easily define your own.

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

This builds on the "manual method" you provide, but, like zip, can be used for any number of dictionaries.

>>> 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)]

When only one dictionary is provided as an argument, it essentially returns dct.items().

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

With no dictionaries, it returns an empty generator (just like zip())

>>> list(common_entries())
[]
like image 142
Volatility Avatar answered Oct 17 '22 18:10

Volatility


The object returned by dict.keys() (called a dictionary key view) acts like a set object, so you can just take the intersection of the keys:

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

common_keys = da.keys() & db.keys()

for k in common_keys:
    print(k, da[k], db[k])

On Python 2 you'll need to convert the keys to sets yourself:

common_keys = set(da) & set(db)

for k in common_keys:
    print k, da[k], db[k]
like image 35
Koreth Avatar answered Oct 17 '22 17:10

Koreth


Dictionary key views are already set-like in Python 3. You can remove set():

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

In Python 2:

for key in da.viewkeys() & db.viewkeys():
    print key, da[key], db[key]
like image 6
pylang Avatar answered Oct 17 '22 18:10

pylang


In case if someone is looking for generalized solution:

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))

or if you like to separate key from values and use syntax like

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

we can replace last line with

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

Tests

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))

gives us

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

(tested on Python 2.7.12 & Python 3.5.2)

like image 1
Azat Ibrakov Avatar answered Oct 17 '22 16:10

Azat Ibrakov