Unit 07 · lesson

Aggregate Data Without Losing the Evidence

Arrays become useful when one algorithm can operate across the whole dataset.

Suppose:

int[] scores = {80, 92, 71, 88, 95};

A running total:

int total = 0;

for (int score : scores) {
    total += score;
}

After the loop, total represents the sum of all processed elements.

The invariant is:

Before each iteration, total equals the sum of the scores already processed.

Average requires the count too

double average = (double) total / scores.length;

What about an empty array? Division by zero becomes the boundary problem again.

A method should make the empty-data rule explicit.

double average(int[] scores) {
    if (scores.length == 0) {
        throw new IllegalArgumentException("scores cannot be empty");
    }

    int total = 0;
    for (int score : scores) {
        total += score;
    }
    return (double) total / scores.length;
}

Minimum and maximum need a starting rule

A tempting maximum implementation is:

int max = 0;

That fails if every legitimate value is negative.

If the array must be nonempty, initialize from real data:

int max = values[0];

for (int value : values) {
    if (value > max) {
        max = value;
    }
}

Now the initial candidate came from the dataset.

This is a reusable algorithm-design lesson: choose initial state from the actual domain, not from a convenient magic number.

Preserve provenance while calculating

If your program prints only:

average = 85.2

a reviewer cannot verify which values produced it.

For learning evidence, preserve:

input array -> algorithm -> result

You do not need to log every internal state forever in production software. During design and testing, traceability makes incorrect assumptions visible.

Build three aggregators

Create methods for:

  • sum;
  • average;
  • maximum.

Test with:

int[] a = {3, 5, 7};
int[] b = {10};
int[] c = {-8, -2, -11};

For empty data, define the contract explicitly instead of improvising a fake average or maximum.

Challenge: count matches

Write:

int countAtLeast(int[] values, int threshold)

It should count how many elements are greater than or equal to the threshold.

Test thresholds below all values, equal to an existing value, between values, and above all values.

Evidence

Submit one aggregation trace showing the running state after each element, plus a test table that includes a dataset capable of exposing a bad initialization strategy.

If your maximum method is tested only with positive values, you have not tested the assumption that 0 is a safe starting value.