1

Question

I have a flat array of objects I'd like to turn into a nested tree. I've tried using both recursion and reduce but haven't quite got the desired effects.

Specifically I have the array:

const rawdata = [
  {name: "A", parent: "All", value: null},
  {name: "C", parent: "A", value: 10},
  {name: "D", parent: "A", value: 20},
  {name: "E", parent: "A", value: 30},
  {name: "B", parent: "All", value: null},
  {name: "F", parent: "B", value: 10},
  {name: "G", parent: "B", value: 20},
  {name: "H", parent: "B", value: 30}
]

Desired Result

And I'd like to turn this into:

let result = {name: "All",
  children: 
   [
     {name: "A",
      children: [
       {name: "C", value: 10},
       {name: "D", value: 20},
       {name: "E", value: 30},
      ],
      value: null,
     },
     {name: "B",
      children: [
       {name: "F", value: 10},
       {name: "G", value: 20},
       {name: "H", value: 30},
      ],
      value: null
     }
   ]
  }

What I've tried:

I've been able to use recursion to create a tree where All is at the top most layer using the name and parent values, but I haven't been able to figure out how to retain the values as part of the object.

let makeTree = (categories, parent) => {
  let node = {}
  categories
    .filter(c => c.parent === parent)
    .forEach(c => node[c.name] = 
      makeTree(categories, c.name))
  return node
}
console.log(JSON.stringify(makeTree(rawdata, "All")), null, 2)

tried applying code from this post Create an tree of objects from arrays but my scenario is a bit different. Any help appreciated!

I also tried using: Build tree array from flat array in javascript

const nest = (items, id = null, link = 'parent_id') =>
  items
    .filter(item => item[link] === id)
    .map(item => ({ ...item, children: nest(items, item.id) }));
console.log(nest(rawdata, id = 'name', link = 'parent'))

But couldn't get this to work either?

MayaGans
  • 1,815
  • 9
  • 30

1 Answers1

1

My proposal...

const makeTree = arr =>
    arr.reduce((r,{name,parent,value,...others},i) =>
    {
    let refParent = r.pKeys.find(x=>x.name===parent)

    if (!refParent) // --> parent==='All'
      {
      r.res.name     = parent
      r.res.children = [] 
      refParent      = { name: parent, children: r.res.children }
      r.pKeys.push( refParent )
      }
    let newRow = {  name, value, ...others }
    if (value===null) 
      {
      newRow.children = []
      r.pKeys.push( { name, children: newRow.children } )
      }
    refParent.children.push( newRow )

    if (i===r.end) return r.res
    return r
    }
    ,{ end:arr.length -1, res:{}, pKeys:[] })
  ;


// show testing with 3 levels, and additinnal (optionnals) infos
const rawdata = 
  [ { name: 'A',  parent: 'All', value: null } 
  , { name: 'C',  parent: 'A',   value: 10   }
  , { name: 'D',  parent: 'A',   value: 20   , info1: 'ty', info2: 'zb' }
  , { name: 'E',  parent: 'A',   value: 30   , info1: 'kg', info2: 'zc' }  
  , { name: 'B',  parent: 'All', value: null } 
  , { name: 'F',  parent: 'B',   value: 10   , info1: 'xyz' } 
  , { name: 'G',  parent: 'B',   value: null } 
  , { name: 'H',  parent: 'B',   value: 30   , info1: 'abc' } 
  , { name: 'g1', parent: 'G',   value: 20   , info1: 'gg1' } 
  , { name: 'g2', parent: 'G',   value: 20   , info1: 'gg2' } 
  , { name: 'g3', parent: 'G',   value: 20   , info1: 'ggg' } 
  ] 

let result = makeTree( rawdata )

console.log( result  )
.as-console-wrapper { max-height: 100% !important; top: 0; }

I started writing this solution just before it was classified as Duplicate. I was just at the beginning of the copy of my prepared code but I discovered buggs there, I deleted it: / When I wanted to come back with my corrections the question had become filed in Duplicate.

There were also some inaccuracies, I wanted to be sure of the validity of my code. I remain a programmer, the desire to finalize code is stronger.

I looked at the duplicate link responses. I only partially looked at the 30 different answers

My solution is the only one to do everything with a simple and unique array.reduce (), and without using external variables.

This is the second reason why I am reactivating my answer here. The first being of course to present it to the PO.

Mister Jojo
  • 20,093
  • 6
  • 21
  • 40