Coding Interview Workshop · Lesson 2

Expose repeated enumeration and allocation

An IEnumerable is a recipe for obtaining an enumerator, not necessarily a saved collection.

Clarify the observable contract

An IEnumerable is a recipe for obtaining an enumerator, not necessarily a saved collection. The task asks for both sum and count from a repeatable source while making source visits visible. One version enumerates twice; the other materializes once. Both return the same values, but they deliberately trade a stored array for one fewer traversal.

Ask whether the source is repeatable and whether the statistics must describe the same observation. A lazy query over mutable state might produce different data on the second traversal. A snapshot can therefore provide semantic consistency in addition to reducing repeated source work, although concurrent writers still need a defined snapshot boundary.

Walk through the verified program

Sum visits two, four and six, producing twelve; Count then visits those three values again, giving six visits overall. After resetting the counter, ToArray visits the source three times total and stores three integers. Sum over that array and Length do not execute the original iterator again. The printout measures visits, not allocations or elapsed time.

The local counter increments immediately before each yielded value, which makes it an observation of original-source production. It does not count later array reads. Writing down the two enumeration phases prevents a misleading conclusion that Count is always constant-time merely because it is constant-time for some collection implementations.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;

int visits = 0;
IEnumerable<int> Source() { foreach (int x in new[] { 2, 4, 6 }) { visits++; yield return x; } }
var repeated = Source(); int sum = repeated.Sum(); int count = repeated.Count();
Console.WriteLine($"repeated:{sum}/{count};visits:{visits}");
visits = 0; int[] snapshot = Source().ToArray();
Console.WriteLine($"snapshot:{snapshot.Sum()}/{snapshot.Length};visits:{visits}");

Account for time, storage and allocations

Both versions are O(n) in big-O time because two times n remains linear. The snapshot version allocates O(n) additional storage, whereas a fused one-pass sum-and-count loop can use O(1) auxiliary state for this task. Source cost and repeatability can matter more than the asymptotic label.

Compare three implementations rather than assuming a copy is the only remedy: repeated enumeration, one materialized snapshot and one fused aggregate. For a finite stream needed only once, the fused version can use constant extra state. If later consumers need individual values, that optimization may fail their actual requirements.

Review assumptions and likely defects

A second enumeration might perform I/O again, observe changed values or be unsupported. Calling ToArray everywhere is not a free optimization: it changes evaluation timing and retains all items. An array visit counter is evidence about traversal count, not proof of zero allocation or a performance benchmark.

Method names do not establish costs independently of the source type. Count on an iterator may execute every element; reading an array Length does not. Likewise, a microbenchmark with a three-element source would be dominated by setup and runtime effects, so this lesson makes no elapsed-time or allocated-byte claim.

Practice one: discriminate edge cases

Replace the snapshot with one foreach loop that accumulates sum and count using checked arithmetic. Hint: no downstream consumer needs the individual elements here. Verify the same twelve and three while keeping source visits at three.

Use an all-negative input when adding a maximum statistic so an accidental zero initializer fails. Keep an explicit empty-input policy for that statistic. A sum identity of zero is mathematically appropriate here, but it does not automatically justify using zero for minimum, maximum or a missing first element.

Practice two: defend an extension

Design a statistics API for a one-shot input with a maximum item budget. Decide whether to reject an oversized sequence, return a truncated result or stream partial statistics; specify which resource is bounded and how enumeration is disposed on failure.

A bounded statistics API can accept a maximum element count, stop with a named over-limit failure and dispose its enumerator through a using scope. It should say whether partial statistics are observable after failure. Returning a result only on successful completion preserves a simple all-or-error contract without retaining every input value.

Evaluate correctness and interview reasoning

Review the claimed optimization along three axes: source traversals, retained storage and result semantics. The supplied output proves six original visits versus three while both versions compute twelve and three. It proves neither allocation freedom nor universal speed. A good answer explains why big-O can remain linear despite a meaningful reduction in costly traversal, then considers a fused aggregate when values need not be retained. For one-shot or changing inputs, correctness can determine the design before performance does. That distinction is more useful in an interview than replacing every query with an array by habit.

A working example

using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;

int visits = 0;
IEnumerable<int> Source() { foreach (int x in new[] { 2, 4, 6 }) { visits++; yield return x; } }
var repeated = Source(); int sum = repeated.Sum(); int count = repeated.Count();
Console.WriteLine($"repeated:{sum}/{count};visits:{visits}");
visits = 0; int[] snapshot = Source().ToArray();
Console.WriteLine($"snapshot:{snapshot.Sum()}/{snapshot.Length};visits:{visits}");

Expected output

repeated:12/3;visits:6
snapshot:12/3;visits:3
Try this
Replace the snapshot with one foreach loop that accumulates sum and count using checked arithmetic. Hint: no downstream consumer needs the individual elements here. Verify the same twelve and three while keeping source visits at three.

Further reading

Interview questions for this lesson