parasomnist
parasomnist

Reputation: 318

How can I loop through a flat JS array, turning it into a nested parent/child structure?

What's the best way to loop through a javascript array, looking for elements of interest and, for each one, make the elements in between "children" of the preceding element of interest?

Essentially, I want to go from flat data that looks like:

[
  {
    value: "foo",
    type: "header!"
  },
  {
    value: "bar",
    type: "normal"
  },
  {
    value: "bar",
    type: "normal"
  },
  {
    value: "foo",
    type: "header!"
  },
  {
    value: "bar",
    type: "normal"
  }
]

To something more like:

[
  {
    value: "foo",
    type: "header!",
    children: [
      {
        value: "foo",
        type: "normal"
      },
      {
        value: "bar",
        type: "normal"
      }
    ]
  },
  {
    value: "bar",
    type: "header!",
    children: [
      {
        value: "foo",
        type: "normal"
      }
    ]
  },
]

I think that Array.reduce is what I need here, but I'm struggling with exactly how to make it do what I need.

So far I've tried code that looks like:

const nestedArray = flatArray.map(el => {
    if(el.type === "header!") return {
        type: el.type,
        children: []
    }
})

Upvotes: 0

Views: 317

Answers (1)

georg
georg

Reputation: 214959

Just loop, check the type field and push it either in the main array or in the children of the last header:

data = [
    {value: "foo", type: "header!"},
    {value: "bar", type: "normal"},
    {value: "bar", type: "normal"},
    {value: "foo", type: "header!"},
    {value: "bar", type: "normal"}
]

let tree = [], last

for (let elem of data) {
    if (elem.type === 'header!')
        tree.push(last = {...elem, children: []})
    else
        last.children.push(elem)
}

console.log(tree)

As a general advice, try to avoid functions like map and reduce when manipulating complex data structures. They are far less readable, harder to reason about and much slower than for..of loops.

Upvotes: 2

Related Questions