javascripttreeflat

How to build a tree from flat array of objects


I am trying to build a tree array from a flat array of objects. The category field is structured as an array because it can have n categories

let data = [
  {
    category: [
      "Kat1"
    ],
    otherFields: [
      "Document 1"
    ]
  },
  {
    category: [
      "Kat1"
    ],
    otherFields: [
      "Document 2"
    ]
  },
  {
    category: [
      "Test",
      "Test 2"
    ],
    otherFields: [
      "Document 1"
    ]
  },
  {
    category: [
      "Test",
      "Test 2",
      "Test 3",
      "Test 4",
      "Test 5",
      "Test 6",
      "Test 7",
      "Test 8",
      "Test 9",
      "Test 10",
      "Test 11"
    ],
    otherFields: [
      "Document 1"
    ]
  }
]

It should be

let tree = [
  {
    label: "Kat1",
    children: [
      { label: "Document 1" },
      { label: "Document 2" },
    ]
  },
  {
    label: "Test",
    children: [
      { 
        label: "Test 2",
        children: [
          { label: "Document 1" },
          { 
            label: 'Test 3',
            children: [
              { 
                label: 'Test 4', 
                children: [
                  ...
                ]
              }
            ]
          }
        ]
      },
    ]
  }
]

Is there any article, link solving similar problem? In my last attempt I only got the main categories I fail every time at the documents and sub categories


Solution

  • A simple recursive function will suffice:

    function insert(root, path, label) {
      if (path.length == 0) {
        root.children.push({label})
      } else {
        const [next, ...next_path] = path;
        let next_node = root.children.find(x => x.label == next);
        if (typeof next_node === 'undefined') {
          next_node = {label: next, children: []}
          root.children.push(next_node);
        }
        insert(next_node, next_path, label);
      }
    }
    
    let root = { label: "root", children: [] }
    
    for (let o of data) {
        insert(root, o.category, o.otherFields[0])
    }