Суммарный список сложных словарей - PullRequest
1 голос
/ 26 апреля 2020

У меня есть список сложных данных, которые я хочу объединить в один объект на date и составить сумму для некоторых полей, таких как totalCost, gross et c. Но я не могу найти хороший и быстрый способ сделать это.

[
  {
    "name": "Period 40",
    "metadata": {
      "payPeriod": "Weekly",
      "startDate": "2020-01-03",
      "totalCost": 4779.27,
      "gross": 4798.81
    }
  },
  {
    "name": "Period 40",
    "metadata": {
      "payPeriod": "Weekly",
      "startDate": "2020-01-03",
      "totalCost": 2857.88,
      "gross": 2918.66
    }
  }
]

Я попытался отсортировать эти данные, затем выполнить itertools.groupby, а затем вручную создать новый объект данных и заполнить данные с помощью sum сгруппированного списка.

sorted_pay_runs = sorted(pay_runs,
                         key=lambda obj: obj['metadata']['startDate'],
                         reverse=True)

merged_pay_runs = []
for start_date, pay_run_data in itertools.groupby(
        sorted_pay_runs, lambda obj: obj['metadata']['startDate']):
    pay_run_data = list(pay_run_data)
    merged_obj = pay_run_data[0]
    merged_obj['metadata']['totalCost'] = sum(item['metadata']['totalCost'] for item in pay_run_data)

    merged_pay_runs.append(merged_obj)

1 Ответ

0 голосов
/ 26 апреля 2020

Вы должны группировать на основе комбинированного ключа имени 'Period 40' и даты внутри 'metadata', поэтому все 'Period 40' одной и той же даты суммируются в одну - то же самое для 'Period 41'

This может работать (числа изменились, чтобы упростить математические доказательства для групп и добавлений):

from itertools import groupby

data = [{ "name": "Period 40", "metadata": {  "payPeriod": "Weekly",
      "startDate": "2020-01-03", "totalCost": 5, "gross": 8 } }, 

        {"name": "Period 41", "metadata": { "payPeriod": "Weekly",
      "startDate": "2020-01-03", "totalCost": 2.5, "gross": 3 } },

        { "name": "Period 41", "metadata": {  "payPeriod": "Weekly",
      "startDate": "2020-01-03", "totalCost": 99, "gross": 110 } }, 

        {"name": "Period 40", "metadata": { "payPeriod": "Weekly",
      "startDate": "2020-01-03", "totalCost": 10, "gross": 18 } }]

# groupby needs sorted data - use (name, startdate) to sort by
sorted_data = sorted(data, key=lambda x: (x["name"],x["metadata"]["startDate"]))

# groupby (name, startdate)  
grped = groupby( sorted_data , lambda x: (x["name"],x["metadata"]["startDate"]))

results = []

# key is the combined key (name, startdate), we need to reapply name in the result
for key,value in grped:
    first, *vv = value                # get the first inner grouped result into first
                                      # put the others into vv
    first.update({"name":key[0]})     # add the key back into the grouped thing
    for v in vv:             # add the remaining inner metadatas
        first["metadata"]["totalCost"] += v["metadata"]["totalCost"]
        first["metadata"]["gross"] += v["metadata"]["gross"] 
    results.append(first)


from pprint import pprint
pprint(results)

Вывод:

[{'metadata': {'gross': 26,
               'payPeriod': 'Weekly',
               'startDate': '2020-01-03',
               'totalCost': 15},
  'name': 'Period 40'},

 {'metadata': {'gross': 113,
               'payPeriod': 'Weekly',
               'startDate': '2020-01-03',
               'totalCost': 101.5}, 
  'name': 'Period 41'}]

HTH

...