Middle · Trace · Complexity

Trace the complete program for expose repeated enumeration and allocation. State the exact stdout, then justify the state transitions and relevant edge conditions.

Think through your answer before opening the explanation.

Coding interviews

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}");
Reveal answer and reasoning

The output lines, in order, are “repeated:12/3;visits:6”; “snapshot:12/3;visits:3”. 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.

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. 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.

What a strong answer covers

  • Exact output: repeated:12/3;visits:6 | snapshot:12/3;visits:3
  • Sum visits two, four and six, producing twelve; Count then visits those three values again, giving six visits overall.
  • A second enumeration might perform I/O again, observe changed values or be unsupported.

Common pitfall

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.

Follow-up questions

  1. 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.
  2. What should happen if a one-shot source throws when a second enumerator is requested?

Self-review

Choose what to revisit. These marks are your own assessment and are separate from lesson completion.

Primary references

Open lesson and code ↗

← All interview questions