Home > Software design >  Python combine/group by dictionaries in a list by a value in the dict
Python combine/group by dictionaries in a list by a value in the dict

Time:10-20

I have this data :

[
    {'name': 'INV/2021/0913', 'invoice_date': datetime.date(2021, 3, 12), 'qty_total': 5.0}, 
    {'name': 'INV/2021/0965', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 6.0}, 
    {'name': 'INV/2021/0966', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 7.0}, 
    {'name': 'INV/2021/0967', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 3.0}, 
    {'name': 'INV/2021/0992', 'invoice_date': datetime.date(2021, 3, 15), 'qty_total': 4.0}
]

As it can be seen the middle 3 dicts have same date.

I want to combine the dictionaries having the same invoice_date and sum up the its qty_total. Set the name attribute to "" for the combined dictionaries. The result should look like this:

[
    {'name': 'INV/2021/0913', 'invoice_date': datetime.date(2021, 3, 12), 'qty_total': 5.0}, 
    {'name': '', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 16.0}, 
    {'name': 'INV/2021/0992', 'invoice_date': datetime.date(2021, 3, 15), 'qty_total': 4.0}
]

CodePudding user response:

Consider utilizing a for loop:

import datetime

data = [
    {'name': 'INV/2021/0913', 'invoice_date': datetime.date(2021, 3, 12), 'qty_total': 5.0}, 
    {'name': 'INV/2021/0965', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 6.0}, 
    {'name': 'INV/2021/0966', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 7.0}, 
    {'name': 'INV/2021/0967', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 3.0}, 
    {'name': 'INV/2021/0992', 'invoice_date': datetime.date(2021, 3, 15), 'qty_total': 4.0},
]
invoice_date_to_entry = {}
for entry in data:
    invoice_date = entry['invoice_date']
    if invoice_date not in invoice_date_to_entry:
        invoice_date_to_entry[invoice_date] = entry
    else:
        invoice_date_to_entry[invoice_date]['name'] = ''
        invoice_date_to_entry[invoice_date]['qty_total']  = entry['qty_total']
new_data = list(invoice_date_to_entry.values())
for entry in new_data:
    print(entry)

Output:

{'name': 'INV/2021/0913', 'invoice_date': datetime.date(2021, 3, 12), 'qty_total': 5.0}
{'name': '', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 16.0}
{'name': 'INV/2021/0992', 'invoice_date': datetime.date(2021, 3, 15), 'qty_total': 4.0}

CodePudding user response:

use itertools.groupby

from datetime import datetime
from itertools import groupby

l = [
    {'name': 'INV/2021/0913', 'invoice_date': datetime(2021, 3, 12).date(), 'qty_total': 5.0}, 
    {'name': 'INV/2021/0965', 'invoice_date': datetime(2021, 3, 14).date(), 'qty_total': 6.0}, 
    {'name': 'INV/2021/0966', 'invoice_date': datetime(2021, 3, 14).date(), 'qty_total': 7.0}, 
    {'name': 'INV/2021/0967', 'invoice_date': datetime(2021, 3, 14).date(), 'qty_total': 3.0}, 
    {'name': 'INV/2021/0992', 'invoice_date': datetime(2021, 3, 15).date(), 'qty_total': 4.0}
]
res = []
for k, v in groupby(sorted(l, key=lambda x: x["invoice_date"]), key=lambda x: (x["invoice_date"])):
    val = list(v)
    res.append(
        {"name": " " if len(val)>1 else val[0]["name"], "invoice_date": k, "qty_total": sum(vals["qty_total"] for vals in val)}
    )
print(res)

Output

[{'name': 'INV/2021/0913',
  'invoice_date': datetime.date(2021, 3, 12),
  'qty_total': 5.0},
 {'name': ' ', 'invoice_date': datetime.date(2021, 3, 14), 'qty_total': 16.0},
 {'name': 'INV/2021/0992',
  'invoice_date': datetime.date(2021, 3, 15),
  'qty_total': 4.0}]
  • Related