JimminyCricket
JimminyCricket

Reputation: 381

Reverse Nested Tree with Multiple Top Level Parents & Index

i have the following data structure

[
  {
    id: 1,
    name: 'Top Level Topic 1',
    parentTopic: undefined
  },
  {
    id: 2,
    name: 'Some topic internally',
    parentTopic: 1
  },
  {
    id: 3,
    name: 'Another topic',
    parentTopic: 2
  },
  { id: 4, name: 'Just another topic', parentTopic: 2 },
  {
    id: 5,
    name: 'Another topic',
    parentTopic: 1
  },
  {
    id: 6,
    name: 'Another topic',
    parentTopic: 5
  },
  {
    id: 7,
    name: 'Another topic',
    parentTopic: 5
  },
  { id: 8, name: 'Another topic', parentTopic: 1 },
  {
    id: 9,
    name: 'Another topic',
    parentTopic: 8
  },
  {
    id: 10,
    name: 'Another topic',
    parentTopic: 9
  },
  {
    id: 11,
    name: 'Another topic',
    parentTopic: 10
  },
  {
    id: 12,
    name: 'Another Top Level Topic',
    parentTopic: undefined
  },
  { id: 13, name: 'Another Important Topic', parentTopic: 12 }]

I am trying to convert & construct it in the following manner

[
  {
    id: 1,
    name: 'Top Level Topic 1',
    parentTopic: undefined,
    index: 1,
    children: [
      {
        id: 2,
        name: 'Some topic internally',
        parentTopic: 1,
        index: 1.1,
        children: [
          {
            id: 3,
            name: 'Another topic',
            parentTopic: 2,
            index: 1.1.1,
            children: []
          },
          {
            id: 4,
            name: 'Just another topic',
            parentTopic: 2,
            index: 1.1.2,
            children: []
          },
        ]
      },
      {
        id: 5,
        name: 'Another topic',
        parentTopic: 1,
        index: 1.2,
        children: [
          {
            id: 6,
            name: 'Another topic',
            parentTopic: 5,
            index: 1.2.1,
            children: []
          },
          {
            id: 7,
            name: 'Another topic',
            parentTopic: 5,
            index: 1.2.2,
            children: []
          },
        ]
      },
      {
        id: 8,
        name: 'Another topic',
        parentTopic: 1,
        index: 1.3,
        children: [
            {
              id: 9,
              name: 'Another topic',
              parentTopic: 8,
              index: 1.3.1,
              children: [
                {
                  id: 10,
                  name: 'Another topic',
                  parentTopic: 9,
                  index: 1.3.1.1,
                  children: []
                },
              ]
            },
        ]
      },
    ]
  },
  {
    id: 12,
    name: 'Another Top Level Topic',
    parentTopic: undefined,
    index: 2
    children: [
      {
        id: 13,
        name: 'Another Important Topic',
        parentTopic: 12,
        index: 2.1,
        children: []
      },
    ]
  },
]

My challenge is that I am not sure how to recursively perform this. Also in the output you will notice an index, which could be nice to generate as one iterates or it could just come from the db, meaning my original data structure would already have it.

I would really appreciate if anyone could help me with this :)

Here is my code which works but at the top level its a dictionary instead of being list of dictionaries

    const invertHierarchy = (arr) => {
      const map = {};
      let root;
      for (const ele of arr) {
        map[ele.id] = ele;
        ele.topics = [];
      }
      for (const ele of arr) {
        if (map[ele.parentTopic] != null) map[ele.parentTopic].topics.push(ele);
        else root = ele;
      }
      return root;
    };

Upvotes: 1

Views: 57

Answers (2)

Nina Scholz
Nina Scholz

Reputation: 386578

You could take another approach by storing all nodes and their parents in an object and take only the array with no parents as result.

By using a single loop, it builds the index as well on the fly.

const
    data = [{ id: 1, name: 'Top Level Topic 1', parentTopic: undefined }, { id: 2, name: 'Some topic internally', parentTopic: 1 }, { id: 3, name: 'Another topic', parentTopic: 2 }, { id: 4, name: 'Just another topic', parentTopic: 2 }, { id: 5, name: 'Another topic', parentTopic: 1 }, { id: 6, name: 'Another topic', parentTopic: 5 }, { id: 7, name: 'Another topic', parentTopic: 5 }, { id: 8, name: 'Another topic', parentTopic: 1 }, { id: 9, name: 'Another topic', parentTopic: 8 }, { id: 10, name: 'Another topic', parentTopic: 9 }, { id: 11, name: 'Another topic', parentTopic: 10 }, { id: 12, name: 'Another Top Level Topic', parentTopic: undefined }, { id: 13, name: 'Another Important Topic', parentTopic: 12 }],
    tree = function(data, root) {
        const t = {};
        data.forEach(o => {
            Object.assign(t[o.id] ??= {}, { ...o });
            ((t[o.parentTopic] ??= {}).children ??= []).push(t[o.id]);
            const index = t[o.parentTopic].index || '';
            t[o.id].index = index + (index && '.') + t[o.parentTopic].children.length;
        });
        return t[root].children;
    }(data, undefined);

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

Upvotes: 0

Andrew Parks
Andrew Parks

Reputation: 8087

const data = [{"id":1,"name":"Top Level Topic 1"},{"id":2,"name":"Some topic internally","parentTopic":1},{"id":3,"name":"Another topic","parentTopic":2},{"id":4,"name":"Just another topic","parentTopic":2},{"id":5,"name":"Another topic","parentTopic":1},{"id":6,"name":"Another topic","parentTopic":5},{"id":7,"name":"Another topic","parentTopic":5},{"id":8,"name":"Another topic","parentTopic":1},{"id":9,"name":"Another topic","parentTopic":8},{"id":10,"name":"Another topic","parentTopic":9},{"id":11,"name":"Another topic","parentTopic":10},{"id":12,"name":"Another Top Level Topic"},{"id":13,"name":"Another Important Topic","parentTopic":12}];

const getPrefix = (prefix, i) => prefix ? `${prefix}.${i+1}` : `${i+1}`

const f = (arr, parentTopic, prefix) =>
  arr.filter(e=>e.parentTopic===parentTopic).map((e,i)=>({
    ...e,
    index: getPrefix(prefix,i),
    children: f(arr, e.id, getPrefix(prefix,i))
}))

console.log(f(data))

Upvotes: 2

Related Questions