CodingNeed.

3 · Reliability and project · 45 MIN

Project · A tested expense report

Pure calculations make success and failure easy to verify.

This report groups whole-unit amounts in a Dictionary and uses checked addition. An invalid record or overflow throws before the method returns its local dictionary, so callers receive either a complete result or a failure. The example’s small Check helper runs regardless of build configuration. Convert these checks to your preferred test framework when the project grows. Persisting balances would require a transaction; this in-memory function deliberately does not imply cross-request or cross-server durability.

Keep the dictionary local until every row has passed validation.

Read the example

using System;
using System.Collections.Generic;
static Dictionary<string,int> Report((string Category,int Amount)[] rows) {
  var totals = new Dictionary<string,int>();
  foreach (var row in rows) {
    if (string.IsNullOrWhiteSpace(row.Category) || row.Amount < 0) throw new ArgumentException("Invalid expense");
    totals.TryGetValue(row.Category, out var previous);
    totals[row.Category] = checked(previous + row.Amount);
  }
  return totals;
}
static void Check(bool ok) { if (!ok) throw new Exception("Check failed"); }
Check(Report(Array.Empty<(string,int)>()).Count == 0);
Check(Report(new[]{("food",5),("food",7)})["food"] == 12);
Console.WriteLine("report checks passed");
Check the expected output
report checks passed

Your challenge

Build a test project covering grouping, invalid records and overflow; add stable sorted report formatting without changing calculation order.

Solution cost: Expected O(n) grouping with O(k) category storage. time · Account for collection storage separately from the returned result. space

Common trap

Returning partial results after a caught exception silently changes an all-or-nothing contract.

Study the project implementation
using System;
using System.Collections.Generic;
static Dictionary<string,int> Report((string Category,int Amount)[] rows) {
  var totals = new Dictionary<string,int>();
  foreach (var row in rows) {
    if (string.IsNullOrWhiteSpace(row.Category) || row.Amount < 0) throw new ArgumentException("Invalid expense");
    totals.TryGetValue(row.Category, out var previous);
    totals[row.Category] = checked(previous + row.Amount);
  }
  return totals;
}
static void Check(bool ok) { if (!ok) throw new Exception("Check failed"); }
Check(Report(Array.Empty<(string,int)>()).Count == 0);
Check(Report(new[]{("food",5),("food",7)})["food"] == 12);
Console.WriteLine("report checks passed");

Further reading: Official documentation

Essential cookies keep your account signed in. Optional analytics is not configured on this site. Your choice does not affect access to lessons.

Read the Privacy Policy. You can change this choice in the footer.