← Back to Blog

Calories Tracker Project — Round 4

We have one report. Let's build the second — and raise the bar a little.

The detailed view shows us what we ate. The weekly summary shows us how much — and whether we stayed on target. Calories consumed per day, compared against a personal goal. Math enters the picture.

We start the same way we always do.

# def add_food_item(): [...]
# def last_days_details(): [...]
# def print_details(): [...]

def last_days_sum():
    pass

And we accelerate. We've already written similar logic in last_days_details() — we copy it as a starting point and adapt.

def last_days_sum():
    today_string = datetime.datetime.now().strftime("%Y-%m-%d")
    last_days_dict = {}
    for key in food_dict:
        if today_string == key.split(",")[0]:
            last_days_dict[key] = food_dict[key]
    return last_days_dict

Two changes immediately. First — we don't need the full list of values per entry, just the calories: food_dict[key][3]. Second — we don't need the full timestamp as a key. We need the date only: key.split(",")[0]. Multiple entries on the same day should add up, not overwrite each other.

That means we need a counter per day. We initialize it to 0 the first time we see a date, then accumulate. This is the correct pattern:

def last_days_sum():
    today_string = datetime.datetime.now().strftime("%Y-%m-%d")
    last_days_dict = {}
    for key in food_dict:
        if today_string == key.split(",")[0]:
            if key.split(",")[0] not in last_days_dict:
                last_days_dict[key.split(",")[0]] = 0
            last_days_dict[key.split(",")[0]] += food_dict[key][3]
    return last_days_dict

We check if the date already exists in last_days_dict before initializing. If we initialized unconditionally — outside the check — we'd reset to 0 on every iteration, losing everything accumulated before. The if key not in guard makes sure we only create the key once.

Now — two upgrades. We want to look at any reference date, not just today. And we want to compare against a personal calorie target. Both inputs we've already written before — we adapt them here.

def last_days_sum():
    today_string = ""
    while not today_string:
        today_string = input("Reference date (YYYY-MM-DD, e.g. 2025-04-02): ")

    while True:
        try:
            calories_target = int(input("Your daily calories target: "))
            if calories_target > 0:
                break
            print("Target must be greater than 0.")
        except ValueError:
            print("Invalid calories target. Enter a whole number.")

    last_days_dict = {}

    for key in food_dict:
        if today_string == key.split(",")[0]:
            if key.split(",")[0] not in last_days_dict:
                last_days_dict[key.split(",")[0]] = 0
            last_days_dict[key.split(",")[0]] += food_dict[key][3]

    return last_days_dict

At this point, last_days_dict holds one integer per day — the total calories consumed. But we need more than a number. We need the number and a verdict. So we loop through the dictionary a second time and replace each integer value with a list that holds both.

The key stays the same. The value changes type — from int to list. Python allows this. A dictionary doesn't enforce what type its values are. We use that flexibility deliberately here.

    for key in last_days_dict:
        if last_days_dict[key] <= calories_target:
            cal_value = last_days_dict[key]
            last_days_dict[key] = [cal_value, "On target! Great job!"]
        else:
            cal_value = last_days_dict[key]
            cal_diff = cal_value - calories_target
            last_days_dict[key] = [cal_value, "Over target by " + str(cal_diff) + " kcal."]

    return last_days_dict

Note the correction on cal_diff: we subtract calories_target from cal_value — not the other way around. We want to know how many calories over the target we went, not zero.

It feels a little like training a model — feeding data in, getting a labeled output back. It isn't, of course. But it's not entirely different either. Large things are built from small concepts. This is one of them.

The full function:

def last_days_sum():
    today_string = ""
    while not today_string:
        today_string = input("Reference date (YYYY-MM-DD, e.g. 2025-04-02): ")

    while True:
        try:
            calories_target = int(input("Your daily calories target: "))
            if calories_target > 0:
                break
            print("Target must be greater than 0.")
        except ValueError:
            print("Invalid calories target. Enter a whole number.")

    last_days_dict = {}

    for key in food_dict:
        if today_string == key.split(",")[0]:
            if key.split(",")[0] not in last_days_dict:
                last_days_dict[key.split(",")[0]] = 0
            last_days_dict[key.split(",")[0]] += food_dict[key][3]

    for key in last_days_dict:
        if last_days_dict[key] <= calories_target:
            cal_value = last_days_dict[key]
            last_days_dict[key] = [cal_value, "On target! Great job!"]
        else:
            cal_value = last_days_dict[key]
            cal_diff = cal_value - calories_target
            last_days_dict[key] = [cal_value, "Over target by " + str(cal_diff) + " kcal."]

    return last_days_dict

Now we display it. Same pattern as before — a dedicated print function, calling last_days_sum() internally.

def print_target():
    food_log = last_days_sum()
    for key in sorted(food_log):
        print(f"Date: {key} - {food_log[key][0]} kcal consumed. {food_log[key][1]}")

sorted(food_log) iterates over the dictionary keys in alphabetical order. Our keys are dates in YYYY-MM-DD format — and for this format, alphabetical order and chronological order are identical. So sorted() gives us the days from oldest to newest, with no extra work.

Into the menu:

while True:
    option = input("Choose option (1-Add, 2-Show food details, 3-Discipline analysis, q-Quit): ")
    if option == "1":
        add_food_item()
        print("Food log added successfully!")
    elif option == "2":
        if len(last_days_details()):
            print_details()
        else:
            print("No data available.")
    elif option == "3":
        if len(last_days_sum()):
            print_target()
        else:
            print("No data available.")
    elif option == "q":
        break
    else:
        print("Invalid option!")

Option 3 — Discipline analysis. The name was chosen deliberately. Not "calorie report". Not "weekly summary". Discipline — because that's what it measures.

The output for a few days might look like this:

Date: 2025-04-01 - 1840 kcal consumed. On target! Great job!
Date: 2025-04-02 - 2210 kcal consumed. Over target by 210 kcal.
Date: 2025-04-03 - 1950 kcal consumed. On target! Great job!

We're not just collecting data anymore. We're evaluating it.

The fire is holding. We have light, we have heat — and now we're starting to cook with it.

One report left. Then we make everything permanent.

[ login to bookmark ] // copied! 4 views · 4 min
// resources
Exercise calories_tracker_r4.py
← prev Calories Tracker Project — Round 3
// 0 comments
// No comments yet. Be the first.
// leave a comment

// Your comment will appear after approval.