Javascript: анализ и сортировка плоской структуры JSON на вложенные массивы?

Я начинаю с простого ввода JSON как такового (простой пример):

[
{id:1, value:'child1', parentId:2, sortOrder:1},
{id:2, value:'root1', parentId:null, sortOrder:1},
{id:3, value:'root2', parentId:null, sortOrder:2},
{id:4, value:'child2', parentId:1, sortOrder:2},
{id:5, value:'root3', parentId:null, sortOrder:3},
{id:6, value:'child1', parentId:2, sortOrder:1},
{id:7, value:'root4', parentId:null, sortOrder:4}
];

Входные данные могут иметь произвольную глубину и длину и должны быть переформатированы в коллекцию вложенных массивов на основе отношений родитель-потомок, а также отсортированы в порядке возрастания на каждом уровне вложенности.

Для форматирования выходных данных можно использовать как собственный JS, так и UnderscoreJS.

Вывод будет отформатирован как структура json с базовой формой:

root1 
  child1
  child2
root2
  child1
    child1
    child2
  child2

  etc...

Где каждый элемент является объектом JSON.

Глубина вложения может быть любой, поскольку данные, скорее всего, поступают из таблицы БД с указанной выше плоской структурой.

Какие-нибудь мысли?

2 ответа

Наш план будет состоять в том, чтобы переместить дочерние элементы под родительским (в новый массив children свойство), а затем отфильтровать их.

const flat = [
{id:1, value:'child1', parentId:2, sortOrder:1},
{id:2, value:'root1', parentId:null, sortOrder:1},
{id:3, value:'root2', parentId:null, sortOrder:2},
{id:4, value:'child2', parentId:1, sortOrder:2},
{id:5, value:'root3', parentId:null, sortOrder:3},
{id:6, value:'child1', parentId:2, sortOrder:1},
{id:7, value:'root4', parentId:null, sortOrder:4}
];

const nested = flat.filter((elt, idx, arr) => {
  const parent = arr.find(e => e.id === elt.parentId);
  if (!parent) return true;
  (parent.children = parent.children || []).push(elt);
});

console.log(nested);

Сортировка останется в качестве упражнения.

Я бы сделал эту работу следующим образом. Я мог бы использовать value свойства, чтобы прикрепить вложенные объекты, но вопрос был неясным на тот момент. Вместо этого я создал children свойства для построения вложенной структуры.

var flat = [
{id:1, value:'child1', parentId:2, sortOrder:1},
{id:2, value:'root1', parentId:null, sortOrder:1},
{id:3, value:'root2', parentId:null, sortOrder:2},
{id:4, value:'child2', parentId:1, sortOrder:2},
{id:5, value:'root3', parentId:null, sortOrder:3},
{id:6, value:'child1', parentId:2, sortOrder:1},
{id:7, value:'root4', parentId:null, sortOrder:4}
],
     lut = flat.sort((a,b) => a.sortOrder - b.sortOrder)
               .reduce((t,o) => { o.children === void 0 && (o.children = []);
                                  t[o.id] = t[o.id] === void 0 ? o : (o.children = t[o.id].children,o);
                                  o.parentId     !== null &&
                                  (t[o.parentId] !== void 0 ? t[o.parentId].children.push(o)
                                                            : t[o.parentId] = {id: o.parentId, children: [o]});
                                  return t;
                                },{}),
  nested = Object.keys(lut).reduce((a,k) => lut[k].parentId === null ? a.concat(lut[k]): a,[]);
console.log(nested);

Так же sort этап не будет необходимым, если вы хотите разместить дочерние объекты в родительском children свойство массива так, как вы их получаете.

Другие вопросы по тегам