pythonpython-3.xdictionary

Calculating sums of nested dictionaries into the dictionary


I'm writing a program that helps collate data from a few sources to perform analysis on.

I currently have a dictionary that looks like this:

output = {
            "main":
                {
                    "overall":
                        {
                            "overall":
                                {
                                    "total": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Profit": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Loss": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                },
                            "Sub A":
                                {
                                    "total": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Profit": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Loss": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                },
                            "Sub B":
                                {   "total": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Profit": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Loss": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                },
                        },
                    "A":
                        {
                            "overall":
                                {
                                    "total": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Profit": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Loss": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                },
                            "Sub A":
                                {
                                    "total": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Profit": {"q1": 10,"q2": 8,"q3": 19,"q4": 7},
                                    "Loss": {"q1": 4,"q2": 2,"q3": 6,"q4": 10},
                                },
                            "Sub B":
                                {   "total": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Profit": {"q1": 50,"q2": 70,"q3": 54,"q4": 77},
                                    "Loss": {"q1": 2,"q2": 8,"q3": 5,"q4": 40},
                                },
                        },
                    "B": 
                        {
                            "overall":
                                {
                                    "total": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Profit": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Loss": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                },
                            "Sub A":
                                {
                                    "total": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Profit": {"q1": 75,"q2": 23,"q3": 25,"q4": 12},
                                    "Loss": {"q1": 64,"q2": 22,"q3": 12,"q4": 5},
                                },
                            "Sub B":
                                {   "total": {"q1": 0,"q2": 0,"q3": 0,"q4": 0},
                                    "Profit": {"q1": 65,"q2": 53,"q3": 3,"q4": 5},
                                    "Loss": {"q1": 10,"q2": 12,"q3": 1,"q4": 2},
                                },
                        }
                },
            },
        },

So far, I have the profit and loss data in the non overall dictionaries.

What I would like to do is have a function that populates the overall totals, profits and losses. For the sake of this, let's just say that profits and losses are aggregated so a profit of 1 and a loss of 1 makes a total of 2.

From looking at some similar questions and some thinking, i have the following:

def calculateOveralls(dictionary, query):
    for a in dictionary[query]: #A.B,C
        for b in dictionary[query][a]: #Sub A, Sub B, Sub C
            if b == "overall":
                pass
            else:
                for c in dictionary[query][a][b]:  # Profit/Loss
                    if c == "total":
                        pass
                    else:
                        for d in dictionary[query][a][b][c]:  # quarters
                            dictionary[query][a][b]["total"][d] = dictionary[query][a][b]["total"][d] + dictionary[query][a][b][c][d]

Any help would be greatly appreciated.

Many thanks!


Solution

  • You appear to have two levels of nested dictionaries within output["main"] and want to generate totals for each quarter and each permutation of level:

    for main_key, main_value in output["main"].items():
        if main_key == "overall":
            continue
        for sub_key, sub_value in main_value.items():
            if sub_key == "overall":
                continue
            for q in ("q1", "q2", "q3", "q4"):
                profit = sub_value["Profit"][q]
                loss = sub_value["Loss"][q]
                sub_value["total"][q] = profit + loss
                output["main"]["overall"]["overall"]["Profit"][q] += profit
                output["main"]["overall"]["overall"]["Loss"][q] += loss
                output["main"]["overall"]["overall"]["total"][q] += profit + loss
                output["main"]["overall"][sub_key]["Profit"][q] += profit
                output["main"]["overall"][sub_key]["Loss"][q] += loss
                output["main"]["overall"][sub_key]["total"][q] += profit + loss
                output["main"][main_key]["overall"]["Profit"][q] += profit
                output["main"][main_key]["overall"]["Loss"][q] += loss
                output["main"][main_key]["overall"]["total"][q] += profit + loss
    
    from pprint import pprint
    
    pprint(output, width=100)
    

    Which outputs:

    {'main': {'A': {'Sub A': {'Loss': {'q1': 4, 'q2': 2, 'q3': 6, 'q4': 10},
                              'Profit': {'q1': 10, 'q2': 8, 'q3': 19, 'q4': 7},
                              'total': {'q1': 14, 'q2': 10, 'q3': 25, 'q4': 17}},
                    'Sub B': {'Loss': {'q1': 2, 'q2': 8, 'q3': 5, 'q4': 40},
                              'Profit': {'q1': 50, 'q2': 70, 'q3': 54, 'q4': 77},
                              'total': {'q1': 52, 'q2': 78, 'q3': 59, 'q4': 117}},
                    'overall': {'Loss': {'q1': 6, 'q2': 10, 'q3': 11, 'q4': 50},
                                'Profit': {'q1': 60, 'q2': 78, 'q3': 73, 'q4': 84},
                                'total': {'q1': 66, 'q2': 88, 'q3': 84, 'q4': 134}}},
              'B': {'Sub A': {'Loss': {'q1': 64, 'q2': 22, 'q3': 12, 'q4': 5},
                              'Profit': {'q1': 75, 'q2': 23, 'q3': 25, 'q4': 12},
                              'total': {'q1': 139, 'q2': 45, 'q3': 37, 'q4': 17}},
                    'Sub B': {'Loss': {'q1': 10, 'q2': 12, 'q3': 1, 'q4': 2},
                              'Profit': {'q1': 65, 'q2': 53, 'q3': 3, 'q4': 5},
                              'total': {'q1': 75, 'q2': 65, 'q3': 4, 'q4': 7}},
                    'overall': {'Loss': {'q1': 74, 'q2': 34, 'q3': 13, 'q4': 7},
                                'Profit': {'q1': 140, 'q2': 76, 'q3': 28, 'q4': 17},
                                'total': {'q1': 214, 'q2': 110, 'q3': 41, 'q4': 24}}},
              'overall': {'Sub A': {'Loss': {'q1': 68, 'q2': 24, 'q3': 18, 'q4': 15},
                                    'Profit': {'q1': 85, 'q2': 31, 'q3': 44, 'q4': 19},
                                    'total': {'q1': 153, 'q2': 55, 'q3': 62, 'q4': 34}},
                          'Sub B': {'Loss': {'q1': 12, 'q2': 20, 'q3': 6, 'q4': 42},
                                    'Profit': {'q1': 115, 'q2': 123, 'q3': 57, 'q4': 82},
                                    'total': {'q1': 127, 'q2': 143, 'q3': 63, 'q4': 124}},
                          'overall': {'Loss': {'q1': 80, 'q2': 44, 'q3': 24, 'q4': 57},
                                      'Profit': {'q1': 200, 'q2': 154, 'q3': 101, 'q4': 101},
                                      'total': {'q1': 280, 'q2': 198, 'q3': 125, 'q4': 158}}}}}
    

    fiddle