'Merging two dictionaries where items are interchanged
Assume I've got the dictionaries:
dict1 = {'A': 1, 'B': 2, 'C' : 3}
dict2 = {'a': 4, 'b': 5, 'c' : 6}
This link suggest several ways to merge the two but all of the merges are simply concatenations. I want to merge them like a dealer shuffles cards, or like a zipper zips. What I mean by this is that once merging dict1 and dict2, the resulting dict3 should become
dict3 = {'A': 1, 'a': 4, 'B': 2, 'b': 5, 'C' : 3, 'c' : 6}
So the merge grabs elements from dict1 and dict2 in an alternating fashion. My dictionaries are in fact very large so doing it manually is not an option.
Solution 1:[1]
There is round-robin itertools recipe to select data this way.
You can use:
dict3 = dict(roundrobin(dict1.items(), dict2.items()))
output:
{'A': 1, 'a': 4, 'B': 2, 'b': 5, 'C': 3, 'c': 6}
from itertools import cycle, islice
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
# Remove the iterator we just exhausted from the cycle.
num_active -= 1
nexts = cycle(islice(nexts, num_active))
You can also use more-itertools.interleave
from more_itertools import interleave
dict(interleave(dict1.items(), dict2.items()))
Solution 2:[2]
Indented for readability:
from itertools import chain
dict(
chain.from_iterable(
zip(dict1.items(), dict2.items())
)
)
If your dictionaries are not guaranteed to be of equal size, adapt this solution to use itertools.zip_longest() instead of basic zip()
Solution 3:[3]
There are many things that could go wrong with this approach. What if your 2 dictionnaries don't have the same length? What if they have duplicate keys? What if later you need 3 dicts instead of 2?
Also, do you have a real use case behind this requirement? Do you really need to build a new dict with all data like this, or do you simply need to iterate over the (key, value) pairs in a specific, alternate fashion like this?
Assuming you don't have to worry about the above, if you only need to iterate, you could simply do something like that:
def iter_zip(dict1, dict2):
for i1, i2 in zip(dict1.items(), dict2.items()):
yield i1
yield i2
dict1 = {'A': 1, 'B': 2, 'C' : 3}
dict2 = {'a': 4, 'b': 5, 'c' : 6}
# you can then do
for key, val in iter_zip(dict1, dict2):
do_something(key, val)
And if you really need to build a new dict, it is now as simple as:
dict(iter_zip(dict1, dict2))
# {'A': 1, 'a': 4, 'B': 2, 'b': 5, 'C': 3, 'c': 6}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | mozway |
| Solution 2 | Klas Å . |
| Solution 3 | Guillaume |
