2

Hi there, I need your help with recursion. I have a source array with objects and I need to regenerate it to result array view. Need to change some data structure.

I've tried to do that on my own but no results for now;(

Each element may have a parrent_id field, nesting can be infinite. How can I do that with recursion?

const source = [
  {
    id: 1,
    title: 'title1',
    alias: 'alias1',
    parent_id: null
  },
  {
    id: 2,
    title: 'title2',
    alias: 'alias2',
    parent_id: null
  },
  {
    id: 3,
    title: 'title3',
    alias: 'alias3',
    parent_id: 2
  },
  {
    id: 4,
    title: 'title4',
    alias: 'alias4',
    parent_id: 2
  },
  {
    id: 5,
    title: 'title5',
    alias: 'alias5',
    parent_id: 4
  },
  {
    id: 6,
    title: 'title6',
    alias: 'alias6',
    parent_id: 4
  }
];

const result = [
  {
    id: 1,
    alias: 'alias',
    title: 'root cat',
    link: '/',
    Icon: 'icon'
  },
  {
    id: 2,
    alias: 'alias',
    title: 'Nested Pages',
    Icon: 'icon',
    items: [
      {
        id: 3,
        alias: 'alias',
        title: 'sub cat for Nested Pages'
      },
      {
        id: 4,
        alias: 'alias',
        title: 'sub cat for Nested Pages',
        items: [
          {
            id: 5,
            alias: 'alias',
            title: 'sub sub cat '
          },
          {
            id: 6,
            alias: 'alias',
            title: 'Level 3'
          }
        ]
      }
    ]
  }
];

Thnx in advance

P.S. Here is my code, it works just for one level nesting. How to solve it to use recursively?

let finArray = [];
const regenArray = (categories, parrent_id = null) => {
  categories.map((el, index, array) => {
    if (el.parent_id === parrent_id) {
      finArray.push(el);
      finArray[finArray.length - 1]['items'] = [];
      categories.map(
        (child_el, child_index, child_array) => {
          if (el.id === child_el.parent_id) {
            finArray[finArray.length - 1]['items'].push(
              child_el
            );
          }
          return false;
        }
      );
    }
  });
};
regenArray(categories);

console.log('finArray', finArray);

3 Answers 3

1

You do not need a recursion, just an object for keeping the reference to node and parent node.

This approach works for unsorted data as well, because it uses both relation from item to parent and from parent to item.

const
    source = [{ id: 1, title: 'title1', alias: 'alias1', parent_id: null }, { id: 2, title: 'title2', alias: 'alias2', parent_id: null }, { id: 3, title: 'title3', alias: 'alias3', parent_id: 2 }, { id: 4, title: 'title4', alias: 'alias4', parent_id: 2 }, { id: 5, title: 'title5', alias: 'alias5', parent_id: 4 }, { id: 6, title: 'title6', alias: 'alias6', parent_id: 4 }],
    tree = function (data, root) {
        var t = {};
        data.forEach(({ parent_id, ...o }) => {
            Object.assign(t[o.id] = t[o.id] || {}, o);
            t[parent_id] = t[parent_id] || {};
            t[parent_id].items = t[parent_id].items || [];
            t[parent_id].items.push(t[o.id]);
        });
        return t[root].items;
    }(source, null);

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

Sign up to request clarification or add additional context in comments.

Comments

0

Iterate through each object of resultant array.if there is no match in objects id to current object's parent id ,do a recursive call to check its items.

 function findParentAndPushChild(object,resArray){
    resArray.forEach( (child)=> {
    if(child.id == object.parent_id)child.items.push(object);
    else if(child.items.length!=0)findParentAndPushChild(object,child.items);
    });
 }

Check the following code snippet.

const source = [{  id: 1,title:'title1',alias:'alias1',parent_id: null},{id: 2,title:'title2',alias: 'alias2',parent_id: null},{id: 3,title:'title3',alias:'alias3',parent_id: 2},{ id: 4,title:'title4',alias:'alias4',parent_id: 2},{id: 5,title:'title5',alias:'alias5',parent_id: 4},{id: 6,title:'title6',alias:'alias6',parent_id: 4}
  ];
let resultArray=[];
source.map( obj =>{obj.items=[];return obj}).forEach(obj=>{
     if(obj.parent_id==null)resultArray.push(obj);
     else{
        let index=resultArray.findIndex( (resObj)=>resObj.id==obj.parent_id);
        if( index == -1)findParentAndPushChild(obj,resultArray) 
        else resultArray[index].items.push(obj);
        }
})
 function findParentAndPushChild(object,resArray){
    resArray.forEach( (child)=> {if(child.id == object.parent_id)child.items.push(object);
    else if(child.items.length!=0)findParentAndPushChild(object,child.items);
    });
 } 
 console.log(resultArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }

1 Comment

thanx so much ;) appreciate your attention
0

First I was trying a tree, but after seen @nina-scholz answer. I decided to write the same code in ES6 manner.

const source = [
  { id: 1, title: "title1", alias: "alias1", parent_id: null },
  { id: 2, title: "title2", alias: "alias2", parent_id: null },
  { id: 3, title: "title3", alias: "alias3", parent_id: 2 },
  { id: 4, title: "title4", alias: "alias4", parent_id: 2 },
  { id: 5, title: "title5", alias: "alias5", parent_id: 4 },
  { id: 6, title: "title6", alias: "alias6", parent_id: 4 }
];
const [result] = source.reduce(
  ([r, map], item) => {
    const d = { ...item, children: [] };
    const loc = map[item.parent_id];
    if (loc) {
      loc.children.push(d);
    } else {
      r.push(d);
    }
    map[item.id] = d;
    return [r, map];
  },
  [[], {}]
);
console.log(JSON.stringify(result, null, 4));
.as-console-row {color: blue!important}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.