1 min lesson
Applying a single edit
Use "Model an edit as a range you cut and a string you splice in" to say what you would do next.
Step 1 of 3
Applying a single editoffset + length + replacement
Model an edit as a range you cut and a string you splice in. The minimal shape is { offset, length, text }: delete length characters at offset, then insert text. Everything harder is built on this.
Learn more
Full explanation
Full explanation
interface Edit { offset: number; // 0-based start in the current buffer length: number; // chars to delete (0 = pure insert) text: string; // chars to insert ('' = pure delete) } function applyEdit(buf: string, e: Edit): string { return buf.slice(0, e.offset) + e.text + buf.slice(e.offset + e.length); }
Composing many edits without corrupting positionswhere off-by-one bugs are born
The trap: every edit you apply shifts the offsets of every later edit. Apply edit A at offset 10 and an edit that used to target offset 50 now targets a different character. Two disciplines avoid the corruption.
- 1Resolve against one snapshot. Compute all edit offsets relative to the original buffer, never against the partially-mutated one.
- 2Apply right-to-left. Sort edits by descending offset and apply from the end of the file backward, so each edit lands before any unprocessed edit's position can shift.
function applyEdits(buf: string, edits: Edit[]): string { const sorted = [...edits].sort((a, b) => b.offset - a.offset); for (const e of sorted) { if (e.offset < 0 || e.offset + e.length > buf.length) { throw new Error(`edit out of range at ${e.offset}`); } buf = buf.slice(0, e.offset) + e.text + buf.slice(e.offset + e.length); } return buf; }
If two edits overlap, you have a conflict, not just a sort order. Detect it: after sorting by offset, if any edit's range intersects the next one's, reject the batch or merge deliberately. Saying this out loud, even if you don't code the merge, shows you've met this bug before.
Empty buffer with one insert. Pure delete at end-of-file. Two adjacent non-overlapping edits. One edit whose range runs off the end - does it throw or silently corrupt? Walk these in the interview; they're the cases that separate correct from almost-correct.
Learn more
Optional practice
Practice: Applying a single edit
QYou must apply a batch of non-overlapping edits to a buffer. Why apply them sorted by descending offset?