Accumulate a running total per category by looping over paired category and value lists. With pandas, df.groupby('cat')['val'].sum() splits the rows by category, applies sum to the value column of each group, and combines the results — the split-apply-combine pattern in one call.

By hand

Loop over zip(cats, vals), accumulating into totals[cat] with .get(cat, 0) to handle first-time keys. Sort the keys for a stable result.

naive.py
Replay: real traced execution (multi-file project)
cats = ['a', 'b', 'a', 'c', 'b', 'a']
vals = [10, 20, 30, 40, 50, 60]
totals = {}
for cat, val in zip(cats, vals):
    totals[cat] = totals.get(cat, 0) + val
result = {k: totals[k] for k in sorted(totals)}
print('RESULT:', result)
  1. cats ← ['a', 'b', 'a', 'c', 'b', 'a']

    1cats = ['a', 'b', 'a', 'c', 'b', 'a']2vals = [10, 20, 30, 40, 50, 60]
    values this step['a', 'b', 'a', 'c', 'b', 'a']cats
  2. vals ← [10, 20, 30, 40, 50, 60]

    1cats = ['a', 'b', 'a', 'c', 'b', 'a']2vals = [10, 20, 30, 40, 50, 60]3totals = {}
    values this step[10, 20, 30, 40, 50, 60]vals
  3. totals ← {}

    2vals = [10, 20, 30, 40, 50, 60]3totals = {}4for cat, val in zip(cats, vals):
    values this step{}totals
  4. cat ← 'a', val ← 10

    3totals = {}4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val
    values this step'a'cat10val
  5. totals ← {'a': 10}

    4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val6result = {k: totals[k] for k in sorted(totals)}
    values this step{} {'a': 10}totals
  6. cat ← 'b', val ← 20

    3totals = {}4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val
    values this step'a' 'b'cat10 20val
  7. totals ← {'a': 10, 'b': 20}

    4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val6result = {k: totals[k] for k in sorted(totals)}
    values this step{'a': 10} {'a': 10, 'b': 20}totals
  8. cat ← 'a', val ← 30

    3totals = {}4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val
    values this step'b' 'a'cat20 30val
  9. totals ← {'a': 40, 'b': 20}

    4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val6result = {k: totals[k] for k in sorted(totals)}
    values this step{'a': 10, 'b': 20} {'a': 40, 'b': 20}totals
  10. cat ← 'c', val ← 40

    3totals = {}4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val
    values this step'a' 'c'cat30 40val
  11. totals ← {'a': 40, 'b': 20, 'c': 40}

    4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val6result = {k: totals[k] for k in sorted(totals)}
    values this step{'a': 40, 'b': 20} {'a': 40, 'b': 20, 'c': 40}totals
  12. cat ← 'b', val ← 50

    3totals = {}4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val
    values this step'c' 'b'cat40 50val
  13. totals ← {'a': 40, 'b': 70, 'c': 40}

    4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val6result = {k: totals[k] for k in sorted(totals)}
    values this step{'a': 40, 'b': 20, 'c': 40} {'a': 40, 'b': 70, 'c': 40}totals
  14. cat ← 'a', val ← 60

    3totals = {}4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val
    values this step'b' 'a'cat50 60val
  15. totals ← {'a': 100, 'b': 70, 'c': 40}

    4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val6result = {k: totals[k] for k in sorted(totals)}
    values this step{'a': 40, 'b': 70, 'c': 40} {'a': 100, 'b': 70, 'c': 40}totals
  16. for cat, val in zip(cats, vals):

    3totals = {}4for cat, val in zip(cats, vals):5    totals[cat] = totals.get(cat, 0) + val
  17. result ← {'a': 100, 'b': 70, 'c': 40}

    5    totals[cat] = totals.get(cat, 0) + val6result = {k: totals[k] for k in sorted(totals)}7print('RESULT:', result)
    values this step{'a': 100, 'b': 70, 'c': 40}result
  18. stdout ← RESULT: {'a': 100, 'b': 70, 'c': 40}

    6result = {k: totals[k] for k in sorted(totals)}7print('RESULT:', result)
    values this stepRESULT: {'a': 100, 'b': 70, 'c': 40}stdout

With pandas

df.groupby('cat')['val'].sum() groups by category, selects the val column, and sums each group. int() converts numpy scalars for a stable result dict.

library.py
import pandas as pd
from dalib.display import set_display
set_display()

cats = ['a', 'b', 'a', 'c', 'b', 'a']
vals = [10, 20, 30, 40, 50, 60]
df = pd.DataFrame({'cat': cats, 'val': vals})
sums = df.groupby('cat')['val'].sum()
result = {k: int(sums[k]) for k in sorted(sums.index)}
print('index:', sorted(sums.index.tolist()))
print('values:', [int(sums[k]) for k in sorted(sums.index)])
print('dtype:', sums.dtype)
print('RESULT:', result)
index: ['a', 'b', 'c']
values: [100, 70, 40]
dtype: int64
RESULT: {'a': 100, 'b': 70, 'c': 40}

Implementation notes

  • groupby('cat')['val'] selects a single column from the grouped object before aggregating. Without the column selection, .sum() would sum every numeric column in the DataFrame.
  • The three-step pattern — groupby (split) → column select → aggregation (apply) → result Series (combine) — is the core of split-apply-combine and applies to all aggregations: sum, mean, min, max, std.
  • Cross-reference: group-sum (python-data-basics) for the pure-Python accumulator version; groupby-mean (this chapter) for the mean variant.