Generate node number based on depth in nested object array

Viewed 81

I have an array that looks like below.

    [
     {
      id: 1,
      name: "task 1",
      children: [
        {
          id: 2,
          name: "task 1.1",
          children: []
        }
      ]
    },
    {
      id: 1,
      name: "task 2",
      children: [
        {
          id: 2,
          name: "task 2.1",
          children: [
            {
              id: 2,
              name: "task 2.1.1",
              children: []
            }
          ]
        }
      ]
    },
    {
      id: 1,
      name: "task 3",
      children: []
    },
  ]

How can I generate a node number for each item according to the depth they are at? Like, the first task's number would be 1, its child would be 1.1, and so on?

Expected output:

[

{
   id: 1,
   name: "task 1",
   taskNumber: "1",
   children: [
     {
       id: 2,
       name: "task 1.1",
       children: [],
       taskNumber: "1.1",
     }
   ]
 },
 {
   id: 1,
   name: "task 2",
   taskNumber: "2",
   children: [
     {
       id: 2,
       name: "task 2.1",
       taskNumber: "2.1",
       children: [
         {
           id: 2,
           name: "task 2.1.1",
           taskNumber: "2.1.1",
           children: []
         }
       ]
     }
   ]
 },
 {
   id: 1,
   name: "task 3",
   taskNumber: "3",
   children: []
  },
]

Please note that the task name can be anything. I want to recursively go through each object and find its task number

3 Answers

You could map an array with new objects and handover the previous taskNumber.

const
    addTaskNumber = (array, parent = '') => array.map(({ children, ...o }, i) => {
        const taskNumber = parent + (parent && '.') + (i + 1);
        return { ...o, taskNumber, children: addTaskNumber(children, taskNumber) };
    }),
    tree = [{ id: 1, name: "task 1", children: [{ id: 2, name: "task 1.1", children: [] }] }, { id: 1, name: "task 2", children: [{ id: 2, name: "task 2.1", children: [{ id: 2, name: "task 2.1.1", children: [] }] }] }, { id: 1, name: "task 3", children: [] }],
    result = addTaskNumber(tree);

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

You can think about recursive with 3 steps:

  1. Determine the key result named keyRes, default it's empty.
  2. Add current task number item.taskNumber = keyRes;
  3. Check if the item has children, then recursive it.

const data = [{id:1,name:"task 1",children:[{id:2,name:"task 1.1",children:[]}]},{id:1,name:"task 2",children:[{id:2,name:"task 2.1",children:[{id:2,name:"task 2.1.1",children:[]}]}]},{id:1,name:"task 3",children:[]}];

function addTaskNumber(array, parent = '') {
    array.forEach((item, index) => {
        const keyRes = parent + (parent && '.') + (index + 1); // Step 1.
        item.taskNumber = keyRes; //Step 2. current task number
        
        if (item.children.length > 0) //Step 3. Recursive base here
          addTaskNumber(item.children, keyRes); // Nested task number
    });
}

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

You can create a helper function like the addTaskNumber below and then map over your data.

const data = [
  {
    id: 1,
    name: "task 1",
    children: [
      {
        id: 2,
        name: "task 1.1",
        children: []
      }
    ]
  },
  {
    id: 1,
    name: "task 2",
    children: [
      {
        id: 2,
        name: "task 2.1",
        children: [
          {
            id: 2,
            name: "task 2.1.1",
            children: []
          }
        ]
      }
    ]
  },
  {
    id: 1,
    name: "task 3",
    children: []
  }
];

const addTaskNumber = (node, number) => {
  const nodeWithTaskNumber = { ...node, taskNumber: number };

  nodeWithTaskNumber.children = nodeWithTaskNumber.children.map(
    (child, index) => addTaskNumber(child, `${number}.${index + 1}`)
  );

  return nodeWithTaskNumber;
}

console.dir(data.map((node, index) => addTaskNumber(node, index + 1)))

Related