2

I am trying to merge my dictionary with same key but it is a little bit different because one of the dictionary is containing a list. I am trying to get an output which will also give me a list back, if there is more than one value in the merged dictionary, like :

{'cartoon':['tom','jerry'],'film':['rose','jack','marry'],'serial':'little boy'}

I am using python 3.7. Is it possible to run the code without using defaultdict? I was also trying to write the print statement like:

print("{'cartoon':"+list(d1(key(value))+list(d2[key]+",'film':"+list(d1(key(value))+list(d2[key]+",'serial':"+list(d1(key(value))+list(d2(key(value))+"}"

but it did not work, so I wrote the following code:

from collections import defaultdict
d1 = {'cartoon': 'tom', 'film': 'rose'}
d2 = {'cartoon': 'jerry', 'film':['jack','marry'], 'serial' : 'little boy'}
new = defaultdict (list)
for char in (d1,d2):
    for key, value in char.iteritems():
        new[key].append(value)
print (new)

I am getting an error saying "AttributError: 'dict' object has no attribute 'iteritems'.

Can anyone suggest it how can I edit this? Thanks in advance.

jpp
  • 159,742
  • 34
  • 281
  • 339
hap
  • 61
  • 8
  • 2
    Which version of Python are you running? I believe that `iteritems` exists only in Python 2 (legacy Python). In either Python 2 or 3 you could use the `get` method of dictionaries to accomplish your purpose without `defaultdict`. Also, the indentation is off your your code: there is no indent between the two `for` loops. – Rory Daulton Jan 27 '19 at 00:00
  • use **.items()** instead of **.iteritems()** – Damian Jan 27 '19 at 00:03
  • `new[key].extend(value if isinstance(value, list) else [value])` – ekhumoro Jan 27 '19 at 00:11
  • Possible duplicate of [Recursively merge dicts so that elements with shared key are combined into a list](https://stackoverflow.com/questions/50441027/recursively-merge-dicts-so-that-elements-with-shared-key-are-combined-into-a-lis) – Olivier Melançon Jan 27 '19 at 01:09

3 Answers3

0

If you've ran this one Python 2, it would work, but since it looks like you're on Python 3, it doesn't, and you would have to replace this line:

    for key, value in char.iteritems():

With:

    for key, value in char.items():

Or the below as the full code would be much shorter:

print({k:(v+[d1[k]] if k in d1 else v) for k,v in d2.items()})
U13-Forward
  • 69,221
  • 14
  • 89
  • 114
0

by list comprehension you can do :

d1 = {'cartoon': 'tom', 'film': 'rose'}
d2 = {'cartoon': 'jerry', 'film':['jack','marry'], 'serial' : 'little boy'}
#normalizing dictionaries
d1={k: v if isinstance(v , list) else [v] for k,v in d1.items()}
d2={k: v if isinstance(v , list) else [v] for k,v in d2.items()}

d3={k:list(set().union(d1.get(k, []),d2.get(k, [])))  for k in  (d1.keys()|d2.keys())}

print(d3)

output:

{'cartoon': ['jerry', 'tom'], 'film': ['marry', 'rose', 'jack'], 'serial': ['little boy']}  

If you want to show single values as string you can do at the end:

d3={k:v if len(v)!=1 else v[0] for k,v in d3.items()}

output:

{'film': ['rose', 'marry', 'jack'], 'serial': 'little boy', 'cartoon': ['tom', 'jerry']}

Maybe this is what you want by saying "all in one line" :

d1 = {'cartoon': 'tom', 'film': 'rose'}
d2 = {'cartoon': 'jerry', 'film':['jack','marry'], 'serial' : 'little boy'}
#normalizing dictionaries
d1={k: v if isinstance(v , list) else [v] for k,v in d1.items()}
d2={k: v if isinstance(v , list) else [v] for k,v in d2.items()}

d3={k:list(set().union(d1.get(k, []),d2.get(k, []))) if len(set().union(d1.get(k, []),d2.get(k, [])))!=1 else list(set().union(d1.get(k, []),d2.get(k, [])))[0]   for k in  (d1.keys()|d2.keys())}

print(d3)
Mehrdad Dowlatabadi
  • 1,335
  • 2
  • 9
  • 11
0

Trying to write your logic in one line isn't likely to yield any benefits. Also note dict.iteritems is deprecated in Python3 in favour of dict.items, which returns a view.

You can rewrite your logic more clearly using list.extend and a ternary statement. The functional solution looks obfuscated at first, but it permits an arbitrary number of input dictionaries, i.e. (d1, d2, d3, ...), without resorting to an explicit nested loop.

from collections import defaultdict
from itertools import chain
from operator import methodcaller

new = defaultdict(list)
for key, value in chain.from_iterable(map(methodcaller('items'), (d1, d2))):
    new[key].extend([value] if not isinstance(value, list) else value)

# defaultdict(list,
#             {'cartoon': ['tom', 'jerry'],
#              'film': ['rose', 'jack', 'marry'],
#              'serial': ['little boy']})
jpp
  • 159,742
  • 34
  • 281
  • 339