Implement Lodash's _.set() for Deep Property Writing

_.set(obj, 'a.b.c', value) writes at an arbitrarily deep path, creating intermediate objects or arrays as needed. The companion to _.get() — harder because you mutate rather than read.

9 min read
JavaScript
Interview
Implementation
Objects

TABLE OF CONTENTS

_.set(obj, 'a.b.c', value) writes a value at an arbitrarily deep path, creating intermediate objects along the way. It's the natural companion to _.get() — and it's harder because you need to mutate rather than just read, and create missing nodes rather than returning a default.


What is _.set()?

set(obj, path, value) writes value at the location described by path, creating any intermediate objects (or arrays) that don't yet exist:

The hard part is determining what to create at each intermediate step: a plain object {} or an array []. The heuristic: if the next key in the path is a valid array index (a non-negative integer), create an array; otherwise create a plain object.

Real-world use cases:

  • Form state — update form.address.city without spread-cloning every layer
  • Config patching — set a deeply nested config value from a flat key path
  • Redux reducers — safely write to nested state paths
  • Template engines — populate nested data structures from dot-notation keys

The Problem

"Implement set(obj, path, value) that writes a value at the nested path. Path can be a dot-notation string like 'a.b.c', bracket notation like 'a[0].b', or an array of keys. Create intermediate objects/arrays as needed."


Thought Process

Two phases:

  1. Parse the path — normalize 'a[0].b' to ['a', '0', 'b'] (always an array of string keys)
  2. Walk and write — traverse the object, creating missing nodes, then set the final key

For step 2: iterate over all keys except the last. At each key, check if the next node exists and is an object. If not, create it — using {} or [] based on whether the next key looks like an array index (/^\d+$/).


Step 1 — Parsing the Path

Loading editor...


Step 2 — Walk and Write

Loading editor...


Step 3 — Overwriting Non-Object Nodes

What if an intermediate node exists but is a primitive? It gets replaced.

Loading editor...


Full Solution

Loading editor...


What Interviewers Are Testing

  • Path normalization — converting bracket notation to dot notation before splitting
  • {} vs [] creation heuristic — using the next key's value to decide what to create: number → array, string → object
  • Primitive overwrite — not assuming existing nodes are objects; replacing them if they're not
  • Mutates in placeset modifies the original object and returns it (Lodash behavior)

Complexity

TimeSpace
set(obj, path, val)O(D) — D = path depthO(D) — path keys array

Interview Tips

  • Handle bracket notation first.replace(/\[(\d+)\]/g, '.$1') before .split('.') is the cleanest path normalization.
  • Explain the {} vs [] decision — "I check whether the next key is a digit. If so, I create an array because integer keys indicate array indexing."
  • Mention immutability — "This mutates the object. For immutable set, you'd create new objects at each level — similar to how Redux reducers work with spread operators."
  • Compare to _.get — "Get traverses and returns; set traverses, creates, and writes. The traversal logic is the same, the write step is new."

Related Questions


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI