0

Suppose I have 2 list of dictionaries of the form:

a = [{'count': 10, 'name': 'ABC', 'dates':{'2018':1,'2019':4,'2020':5}}, {'count': 5, 'name': 'XYZ', 'dates':{'2018':2,'2019':4,'2020':3}}]

b = [{'count': 5, 'name': 'ABC', 'dates':{'2018':3,'2019':1,'2020':3}}, {'count': 3, 'name': 'XYZ', 'dates':{'2018':3,'2019':5,'2020':11}}]

Now i want to merge dictionary b into a such that each number corresponding to same date in a dictionary are added up and I get something of the following sort:

a = [{'count': 15, 'name': 'ABC', 'dates':{'2018':4,'2019':5,'2020':8}}, {'count': 8, 'name': 'XYZ', 'dates':{'2018':5,'2019':9,'2020':14}}]

How can this be achieved? I tried doing it through for loops, but it is turning out very complex. Is there a pythonic way of doing it?

Dhruv Kaushal
  • 201
  • 2
  • 12
  • Please share your tries – azro May 27 '20 at 09:10
  • 1
    Maybe this is related? https://stackoverflow.com/questions/11011756/is-there-any-pythonic-way-to-combine-two-dicts-adding-values-for-keys-that-appe – NewPythonUser May 27 '20 at 09:12
  • @azro tbh it got too complex for me to understand, so I left it midway. – Dhruv Kaushal May 27 '20 at 09:17
  • @NewPythonUser It shows an error : Traceback (most recent call last): File "/home/926b026e392479d8ef2cee8fb8fea506.py", line 4, in print(A + B) File "/usr/lib/python3.6/collections/__init__.py", line 703, in __add__ if newcount > 0: TypeError: '>' not supported between instances of 'str' and 'int'. – Dhruv Kaushal May 27 '20 at 09:17
  • Edit your post to add code or error, not in comment – azro May 27 '20 at 09:18

2 Answers2

3

You could use a Counter to sum the dates' occurences

  • iterate over both dict of a and b
  • use the name as a key, to know whether to add the mapping or compute the sum
  • when just adding, set the dates in a Counter (ready to be used later)
  • when summing, add the previous counter to the new one, they'll sum together their occurences
result = {}
for value in a + b:
    print(value)
    if value['name'] not in result:
        result[value['name']] = value
        result[value['name']]['dates'] = Counter(value['dates'])
    else:
        result[value['name']]['dates'] += Counter(value['dates'])
        result[value['name']]['count'] += value['count']

final_result = list(result.values())
# [{'count': 15, 'name': 'ABC', 'dates': Counter({'2020': 8, '2019': 5, '2018': 4})}, {'count': 3, 'name': 'XYZ', 'dates': Counter({'2020': 14, '2019': 9, '2018': 5})}]
azro
  • 53,056
  • 7
  • 34
  • 70
3

Plain loop solution:

a = [{'count': 10, 'name': 'ABC', 'dates':{'2018':1,'2019':4,'2020':5}}, {'count': 5, 'name': 'XYZ', 'dates':{'2018':2,'2019':4,'2020':3}}]
b = [{'count': 5, 'name': 'ABC', 'dates':{'2018':3,'2019':1,'2020':3}}, {'count': 3, 'name': 'XYZ', 'dates':{'2018':3,'2019':5,'2020':11}}]

# loop over all items in a
for i, aItem in enumerate(a):
    # find corresponding item in b by 'name' use an empty one if not found!
    bItem = [item for item in b if item['name'] == aItem['name']] or [{}]
    bItem = bItem[0]

    # sum up the date values
    _dates = aItem['dates']
    for k,v in _dates.items():
        _dates[k] += bItem.get('dates', {}).get(k, 0)

    aItem['dates'] = _dates
    aItem['count'] += bItem.get('count', 0)

print(a)

Output:

[
{'count': 15, 'dates': {'2020': 8, '2019': 5, '2018': 4}, 'name': 'ABC'},  
{'count': 8, 'dates': {'2020': 14, '2019': 9, '2018': 5}, 'name': 'XYZ'}
]
Maurice Meyer
  • 17,279
  • 4
  • 30
  • 47