-1

I have two dictionaries:

Let's say

MaleDict = {'Jason':[(2014, 394),(2013, 350)...], 'Stephanie':[(2014, 3), (2013, 21),..]....}
FemaleDict = {'Jason':[(2014, 56),(2013, 23)...], 'Stephanie':[(2014, 335), (2013, 217),..]....}

I am attempting to combine the dictionaries so thats

CompleteDict = {'Jason':[(2014, 394, 56),(2013, 350, 23)...], 'Stephanie':[(2014, 3, 335), (2013, 21, 217),..]....}

I am not to good a while loops so i thought i would try and use a list comprehension.

[BaseDict[x].append((i[0], i[1], j[1])) for i in MaleDict[x] for j in FemaleDict[y] if x == y and i[0] == j[0]]

I keep getting a unhashable error. Look like I'm not too good at list comprehensions either lol. Any help would be appreciated.

Python3

  • Will the names and years have one-one correspondence always? – thefourtheye Oct 15 '14 at 05:22
  • Yes, the same names with be in both dictionaries, however the same is not said with the years. Thus, if there is a year in only one dictionary the output may look like {'James':[...,(1999, 150, 0)...] ...} – Jason Halpman Oct 15 '14 at 05:28

2 Answers2

0

for loops are king in python. while loops have their place, but most objects in python can be iterated over using for item in object: syntax.

Here's one way to do it:

from collections import defaultdict

MaleDict = {'Jason':[(2014, 394),(2013, 350)], 'Stephanie':[(2014, 3), (2013, 21),]}
FemaleDict = {'Jason':[(2014, 56),(2013, 23)], 'Stephanie':[(2014, 335), (2013, 217),]}

name_keys = set(MaleDict.keys() + FemaleDict.keys())

combined_names = {}
for name_key in name_keys:
    combined_values = defaultdict(list)
    male_values_dict = dict(MaleDict[name_key])
    female_values_dict = dict(FemaleDict[name_key])
    year_keys = set(male_values_dict.keys() + female_values_dict.keys())
    for year_key in year_keys:
        combined_values[year_key].append(male_values_dict[year_key])
        combined_values[year_key].append(female_values_dict[year_key])
    combined_names[name_key] = dict(combined_values)

Output:

{'Jason': {2013: [350, 23], 2014: [394, 56]},
'Stephanie': {2013: [21, 217], 2014: [3, 335]}}

Or if you perfer to keep the tuple as a value:

from collections import defaultdict

MaleDict = {'Jason':[(2014, 394),(2013, 350)], 'Stephanie':[(2014, 3), (2013, 21),]}
FemaleDict = {'Jason':[(2014, 56),(2013, 23)], 'Stephanie':[(2014, 335), (2013, 217),]}

name_keys = set(MaleDict.keys() + FemaleDict.keys())

combined_names = {}
for name_key in name_keys:
    combined_values = []
    male_values_dict = dict(MaleDict[name_key])
    female_values_dict = dict(FemaleDict[name_key])
    year_keys = set(male_values_dict.keys() + female_values_dict.keys())
    for year_key in year_keys:
        tuple_result = (year_key, male_values_dict[year_key], female_values_dict[year_key])
        combined_values.append(tuple_result)
    combined_names[name_key] = combined_values

Output:

{'Jason': [(2013, 350, 23), (2014, 394, 56)],
 'Stephanie': [(2013, 21, 217), (2014, 3, 335)]}    

note: if in (2014, 394, 56),(2013, 350, 23) 2014 and 2013 are your keys a dictionary is better suited here.

monkut
  • 42,176
  • 24
  • 124
  • 155
0

Have a look to this script:

>>> MaleDict = {'Jason':[(2014, 394),(2013, 350)], 'Stephanie':[(2014, 3), (2013, 21),]}
>>> FemaleDict = {'Jason':[(2014, 56),(2013, 23)], 'Stephanie':[(2014, 335), (2013, 217),]}
>>> 
>>> #clone MaleDict, to have a base to append FemaleItems
... combined_dict = dict(MaleDict)
>>> for name, items in FemaleDict.items():
...     for idx,year_tuple in enumerate(combined_dict.get(name,[])):
...         year_tuple = list(year_tuple) #convert to list to let us modify its items
...         for year_data in items[idx]:  #inspect same year-element of both dicts
...             if year_data not in year_tuple: # if the current part doesn't exist, append it to temp list
...                 year_tuple.append(year_data)
...         combined_dict[name] [idx] = tuple(year_tuple) #finally replace the current tuple by new one
... 
>>> 
>>> combined_dict
{'Jason': [(2014, 394, 56), (2013, 350, 23)], 'Stephanie': [(2014, 3, 335), (2013, 21, 217)]}
xecgr
  • 5,095
  • 3
  • 19
  • 28
  • I forgot to add that I am using Python3. I don't believe iteritems is supported by python3. Is there something else that will work in its place? – Jason Halpman Oct 15 '14 at 06:20
  • It seems that items method will be enought: http://stackoverflow.com/questions/13998492/iteritems-in-python – xecgr Oct 15 '14 at 06:43