call(back)

Key Paths of a Nested Object

Return the path to every primitive in a nested object or array.

InputOutput
{ a: { b: { c: 1 }, d: 2 }, e: 3 }["a.b.c", "a.d", "e"]
[1, { a: 2, b: [3, 4] }, 5]["0", "1.a", "1.b.0", "1.b.1", "2"]

Rules

  • A path joins keys with dots, and array indices are keys too.
  • A primitive is anything that is not an object, plus null. Empty objects and arrays contribute nothing.
  • Paths come out in visiting order: insertion order for objects, index order for arrays.
  • The input is always an object or an array.
  • Inputs may contain cycles. Skip a reference to an object that is already on the current path. The same object reached along two different paths is listed under both.

Hints

Hint 1

Recurse with the path so far. typeof null is "object", so test value === null first.

Hint 2

Object.keys returns index strings for arrays, so one loop covers both shapes.

Hint 3

For cycles, keep a Set of the objects on the current path: add before descending, delete after. A visited set that never forgets would drop the second path to a shared object.

Asked at