11

I'm trying to create a function that might receive as input many or a few dictionaries. I'm using the following code:

def merge_many_dics(dic1,dic2,dic3=True,dic4=True,dic5=True,dic6=True,dic7=True,dic8=True,dic9=True,dic10=True):
"""
Merging up to 10 dictionaries with same keys and different values
:return: a dictionary containing the common dates as keys and both values as values
"""
manydics = {}
for k in dic1.viewkeys() & dic2.viewkeys() & dic3.viewkeys() & dic4.viewkeys() & dic5.viewkeys() & dic6.viewkeys()\
        & dic7.viewkeys() & dic8.viewkeys() & dic9.viewkeys() & dic10.viewkeys():
    manydics[k] = (dic1[k], dic2[k],dic3[k],dic4[k],dic5[k],dic6[k],dic7[k],dic8[k],dic9[k],dic10[k])

return manydics

Note that I'm trying to equal the arguments dic3, dic4, dic5 and so on to "True", so when they are not specified and are called in the function nothing happens. However I'm getting the following error:

Traceback (most recent call last):
File "/Users/File.py", line 616, in <module>
main_dic=merge_many_dics(dic1,dic2,dic3,dic4)
File "/Users/File.py", line 132, in merge_many_dics
& dic7.viewkeys() & dic8.viewkeys() & dic9.viewkeys() & dic10.viewkeys():
AttributeError: 'bool' object has no attribute 'viewkeys'

Anyone to enlight my journey available?

aabujamra
  • 4,494
  • 13
  • 51
  • 101

5 Answers5

13

Using arbitrary argument list, the function can be called with an arbitrary number of arguments:

>>> def merge_many_dics(*dicts):
...     common_keys = reduce(lambda a, b: a & b, (d.viewkeys() for d in dicts))
...     return {key: tuple(d[key] for d in dicts) for key in common_keys}
...
>>> merge_many_dics({1:2}, {1:3}, {1:4, 2:5})
{1: (2, 3, 4)}
falsetru
  • 357,413
  • 63
  • 732
  • 636
6

You should try the args syntax:

def merge_many_dics(*args):
   iterate over your args to join them

then you can call the function with as many arguments as you like.

A function with *args could be as following:

   def print_all(name, *args):
      print "Hello", name, "here are your args"
      for arg in args:
         print arg

   print_all("Claus", "car", "boat", "house")

this will print:

Hello Clause here are your args

car
boat
house
Randrian
  • 1,055
  • 12
  • 25
4

Here is Python 3.x answer based on @falsetru answer and using the operator.and_ function.

>>> from functools import reduce
>>> import operator
>>> def merge_many_dicts(*dicts):
...     common_keys = reduce(operator.and_, (d.keys() for d in dicts))
...     return {key: tuple(d[key] for d in dicts) for key in common_keys}
... 
>>> merge_many_dicts({1:2}, {1:3}, {1:4, 2:5})
{1: (2, 3, 4)}
styvane
  • 59,869
  • 19
  • 150
  • 156
0

As the error says, you cannot view the keys of a boolean, aka, True.viewkeys() does not work. Change your default dictionary's to be empty, leaving:

def merge_many_dics(dic1,dic2,dic3={},dic4={},dic5={},dic6={},dic7={},dic8={},dic9={},dic10={}):
    """
    Merging up to 10 dictionaries with same keys and different values
    :return: a dictionary containing the common dates as keys and both values as values
    """
    manydics = {}
    for k in dic1.viewkeys() & dic2.viewkeys() & dic3.viewkeys() & dic4.viewkeys() & dic5.viewkeys() & dic6.viewkeys()\
            & dic7.viewkeys() & dic8.viewkeys() & dic9.viewkeys() & dic10.viewkeys():
        manydics[k] = (dic1[k], dic2[k],dic3[k],dic4[k],dic5[k],dic6[k],dic7[k],dic8[k],dic9[k],dic10[k])

    return manydics

Here is an implementation in which you create a list for every key and add each item, I'm sure it can be optimized a lot more, but it's very readable:

def merge_many_dicts(*args):
    """
    Merging all dictionaries suposing all dictionaries share keys
    :return: a dictionary containing the common dates as keys and both values as values
    """
    manydicts = {}
    for k in args:
        for key in k.iterkeys():
            manydicts[key] = []
    for k in args:
        for key, value in k.iteritems():
            manydicts[key].append(value)

    return manydicts
byrass
  • 360
  • 2
  • 12
  • It works but the function will return an empty dictionary and that's not the intention – aabujamra Dec 13 '15 at 13:07
  • I would go with the *args aproach, I'll edit my answer – byrass Dec 13 '15 at 13:08
  • 1
    Never use mutable default values. See https://pythonconquerstheuniverse.wordpress.com/2012/02/15/mutable-default-arguments/ Instead use `*args` or use None as the default value. – DeepSpace Dec 13 '15 at 13:13
  • I don't know how to use *args and None returns the same sort of error as I was originally getting with True – aabujamra Dec 13 '15 at 13:14
  • 1
    @abutremutante If you use the `None` approach you should check inside the function whether or not the argument was passed. Use `if dic3 is None` for example, or `if isinstance(dic3, dict)`. But it is better to use `*args` as explained in another answer. – DeepSpace Dec 13 '15 at 13:18
  • 1
    @DeepSpace: mutable default values are quite useful when used correctly, as your link mentions. However, I certainly agree that they should **not** be used for something like this. And because of the problems mentioned in your link and in [“Least Astonishment” in Python: The Mutable Default Argument](http://stackoverflow.com/q/1132941/4014959) it's a Good Idea™ to explicitly comment what you're doing when you do use a mutable default argument. – PM 2Ring Dec 13 '15 at 13:35
0

You can use the following code, to initial those parameters with in the function

def merge_many_dics(dic1, dic2, dic3=None, dic4=None, dic5=None, dic6=None, dic7=None, dic8=None, dic9=None,
                    dic10=None):
    """
    Merging up to 10 dictionaries with same keys and different values
    :return: a dictionary containing the common dates as keys and both values as values
    """
    for item in locals().items():
        if item is None:
            item = dic1

    manydics = {}
    for k in dic1.viewkeys() & dic2.viewkeys() & dic3.viewkeys() & dic4.viewkeys() & dic5.viewkeys() & dic6.viewkeys() \
            & dic7.viewkeys() & dic8.viewkeys() & dic9.viewkeys() & dic10.viewkeys():
        manydics[k] = (dic1[k], dic2[k], dic3[k], dic4[k], dic5[k], dic6[k], dic7[k], dic8[k], dic9[k], dic10[k])

    return manydics
Youan Wang
  • 94
  • 5