Cześć , potrzebuję twojej pomocy z rekurencją. Mam tablicę źródłową z obiektami i muszę ją ponownie wygenerować, aby uzyskać widok tablicy wyników. Trzeba zmienić jakąś strukturę danych.

Próbowałem to zrobić samodzielnie, ale na razie bez rezultatów; (

Każdy element może mieć pole parrent_id, zagnieżdżanie może być nieskończone. Jak mogę to zrobić z rekurencją?

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'
          }
        ]
      }
    ]
  }
];

Z góry dziękuję

P.S. Oto mój kod, działa tylko na jednym poziomie zagnieżdżenia. Jak rozwiązać to, aby używać rekurencyjnie?

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);
2
HeSh 1 kwiecień 2020, 18:54

3 odpowiedzi

Najlepsza odpowiedź

Nie potrzebujesz rekursji, tylko obiekt do przechowywania odniesienia do węzła i węzła nadrzędnego.

To podejście działa również w przypadku niesortowanych danych, ponieważ wykorzystuje zarówno relację od elementu do elementu nadrzędnego, jak i od elementu nadrzędnego do elementu.

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; }
1
Nina Scholz 1 kwiecień 2020, 17:54

Najpierw wypróbowałem drzewo, ale po zobaczeniu odpowiedzi @nina-scholz. Postanowiłem napisać ten sam kod w ES6 sposób.

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}
0
xdeepakv 1 kwiecień 2020, 17:21

Iteruj po każdym obiekcie wynikowej tablicy. Jeśli nie ma dopasowania w id obiektu do identyfikatora rodzica bieżącego obiektu, wykonaj wywołanie rekurencyjne, aby sprawdzić jego elementy.

 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);
    });
 }

Sprawdź poniższy fragment kodu.

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; }
0
M A Salman 1 kwiecień 2020, 16:52