Practice interviews

Why does the same text produce different lines?

A small import function receives text in chunks. Its output changes when the same text is split at a different position.

The question

Fictional exercise. The supplied code, data and outcomes are authored teaching examples, not an employer question or model output.

Authored starting code
function lines(chunks) {
  const result = [];
  for (const chunk of chunks) {
    result.push(...chunk.split('\n').slice(0, -1));
  }
  return result;
}
Invented Two representations of the same input
  • Whole inputOne chunk: 'ab\ncd\n'.
  • Split inputTwo chunks: 'ab' and '\ncd\n'.
Fixed line contract

Only LF completes a line; CR is ordinary text. Preserve empty lines completed by LF. Chunk boundaries have no meaning. At EOF emit a nonempty unfinished tail once. A trailing LF creates no extra empty EOF line. An empty stream gives no lines; empty chunks change nothing.

“Trace the starting code, then define the state needed to preserve the supplied line contract.”

A strong answer, step by step

Open each step in turn. This is one strong answer, not the only one.

Step 1: Keep chunk and line separate

What would you do here? Open the move you’d make.

  • Treat every chunk as a complete line

    Tempting, but it misses something. The same text can arrive at different chunk boundaries.

  • Discard the final fragment of every chunk

    Tempting, but it misses something. That is how the starting code loses ab.

  • Retain an unfinished tail across chunks

    The strong move. The next delimiter can complete the line that began earlier.

See how a strong candidate says it

“A chunk may end halfway through a line. The first chunk 'ab' has no delimiter, so the starting function drops it. The next chunk begins with LF and produces an empty line instead of completing ab.”

What a strong candidate could say

Why it works: A transport chunk does not establish a completed record.

Step 2: Trace the actual mismatch

What would you do here? Open the move you’d make.

  • Show whole and split outputs under the same contract

    The strong move. This isolates the lost carry rather than changing the input meaning.

  • Strip all empty lines

    Tempting, but it misses something. The contract requires legitimate empty lines completed by LF.

  • Add a newline to every chunk

    Tempting, but it misses something. That invents delimiters that were not present.

See how a strong candidate says it

“Whole input yields ab and cd. The split input yields an empty string and cd in this starting code. I would retain carry='ab' after the first chunk, append the next chunk, then extract complete LF-delimited lines.”

What a strong candidate could say

Why it works: The two inputs differ only in chunk boundaries.

Step 3: Make EOF explicit

What would you do here? Open the move you’d make.

  • Always append an empty EOF line

    Tempting, but it misses something. That violates the trailing-LF rule.

  • Emit only a nonempty EOF tail

    The strong move. This preserves both final fragments and the stated delimiter behavior.

  • Drop every final tail

    Tempting, but it misses something. That loses a valid unterminated final line.

See how a strong candidate says it

“After all chunks, emit carry only when it is nonempty. Thus ['ab'] yields ['ab']; ['\n'] yields one empty line; ['ab\n\n'] yields ab and one empty line. A trailing delimiter does not add another EOF line.”

What a strong candidate could say

Why it works: EOF and an LF delimiter have different effects.

Step 4: Choose boundary-independent checks

What would you do here? Open the move you’d make.

  • Test only a newline-terminated whole chunk

    Tempting, but it misses something. That is the starting code's easy path.

  • Normalize CR silently

    Tempting, but it misses something. That introduces behavior outside the supplied contract.

  • Check chunking equivalence and exact EOF examples

    The strong move. The examples exercise the missing carry and finalization rule.

See how a strong candidate says it

“Compare whole and split versions of the same text, plus empty chunks, an empty stream, a real empty line and a nonempty final tail. Preserve CR as text because this contract only names LF.”

What a strong candidate could say

Why it works: The tests should challenge boundaries without changing semantics.

The answer, in short

Decision
Carry unfinished text across chunks and finalize by the stated EOF rule.
Because
Per-chunk splitting loses data when a line spans chunks.
What would change it
A CRLF, encoding or streaming-resource contract would require separate decisions and checks.

Common traps

  • Treating a plausible result as proof of the full contract.
  • Claiming more than the shown inputs and checks establish.

Check your answer

  • Did you show the actual whole/split difference?
  • Did you preserve meaningful empty lines?
  • Did you define the nonempty EOF tail rule?
  • Did the test keep the same text while changing only chunk boundaries?

Last reviewed Nov 10, 2026