Задать вопрос

Как корректно обойти массив для построения дерева?

Необходимо из массива сформировать из вложенную структуру (дерево). Путь для обхода можно взять из поля "name" каждого элемента nodes.

Как определяется вложенность: У каждого элемента есть поле name. Последняя подстрока справа после слэша в этом поле - это title текущего элемента. Далее, чтобы получить родителя или потомков данного элемента, необходимо взять соответственно подстроку слева или подстроку справа от него и таким образом накопить аккумулятор, проходясь по каждому элементу.

У одного элемента в исходной коллекции nodes может быть несколько потомков. Если у элемента потомков нет, то его поле isDirectory === false, в противном случае isDirectory === true.

Исходные данные:
const nodes = [
  {
    "id": 0,
    "name": "\"Корень\"",
    "createDate": "2018-12-11T14:40:26.95",
    "updateDate": "2018-12-11T14:40:26.95",
    "folderId": -1,
    "ctnsCount": 0,
    "ctnsCountDate": "2018-12-11T14:40:26.95",
    "audiences": [0, 0, 0, 0]
  },
  {
    "id": 1000831,
    "name": "\"Store/Сегменты для OPS/Сегменты для внешней рекламы/Автодилеры\"",
    "createDate": "2018-12-29T03:04:28.26",
    "updateDate": "2018-12-29T03:04:28.26",
    "folderId": -1,
    "ctnsCount": 23511,
    "ctnsCountDate": "2019-01-09T05:48:23.487",
    "audiences": []
  },
  {
    "id": 1000249,
    "name": "\"Store/Сегменты для OPS/Сегменты для внешней рекламы\"",
    "createDate": "2018-12-11T14:40:42.313",
    "updateDate": "2018-12-11T14:40:42.313",
    "folderId": -1,
    "ctnsCount": 1490426,
    "ctnsCountDate": "2019-01-09T05:48:04.827",
    "audiences": []
  },
  {
    "id": 1000032,
    "name": "\"Store/Сегменты для OPS\"",
    "createDate": "2018-12-11T14:40:19.48",
    "updateDate": "2018-12-11T14:40:19.48",
    "folderId": -1,
    "ctnsCount": 0,
    "ctnsCountDate": "2018-12-11T14:40:19.48",
    "audiences": []
  },
  {
    "id": 28473,
    "name": "\"Store\"",
    "createDate": "2018-12-11T14:40:32.733",
    "updateDate": "2018-12-11T14:40:32.733",
    "folderId": -1,
    "ctnsCount": 0,
    "ctnsCountDate": "2018-12-11T14:40:32.733",
    "audiences": []
  },
  {
    "id": 1000772,
    "name": "\"Store/Сегменты для OPS/Сегменты для внешней рекламы/Cian\"",
    "createDate": "2018-12-11T14:40:05.02",
    "updateDate": "2018-12-11T14:40:05.02",
    "folderId": -1,
    "ctnsCount": 30409,
    "ctnsCountDate": "2019-01-09T05:48:20.673",
    "audiences": []
  },
  {
    "id": 2681,
    "name": "\"Сегменты Facetz/Образ жизни/Обзоры",
    "createDate": "2018-12-11T14:40:30.623",
    "updateDate": "2018-12-11T14:40:30.623",
    "folderId": -1,
    "ctnsCount": 115379,
    "ctnsCountDate": "2019-01-09T05:48:23.847",
    "audiences": []
  },
  {
    "id": 3840,
    "name": "\"Сегменты Facetz/Образ жизни\"",
    "createDate": "2018-12-11T14:39:46.45",
    "updateDate": "2018-12-11T14:39:46.45",
    "folderId": -1,
    "ctnsCount": 0,
    "ctnsCountDate": "2018-12-11T14:39:46.45",
    "audiences": []
  },
  {
    "id": 3811,
    "name": "\"Сегменты Facetz\"",
    "createDate": "2018-12-11T14:39:46.373",
    "updateDate": "2018-12-11T14:39:46.373",
    "folderId": -1,
    "ctnsCount": 0,
    "ctnsCountDate": "2018-12-11T14:39:46.373",
    "audiences": []
  }
];


Результат:
const result = [
  {
    id: 0,
    title: 'Корень',
    isDirectory: true,
    children: [
      {
        id: 28473,
        title: 'Store',
        isDirectory: true,
        children: [
          {
            id: 1000032,
            title: 'Сегменты для OPS',
            isDirectory: true,
            children: [
              {
                id: 1000249,
                title: 'Сегменты для внешней рекламы',
                isDirectory: true,
                children: [
                  {
                    id: 1000831,
                    title: 'Автодилеры',
                    isDirectory: false,
                  },
                  {
                    id: 1000772,
                    title: 'Cian',
                    isDirectory: false,
                  }
                ] 
              }
            ]
          }
        ]
      },
      {
        id: 3811,
        title: 'Сегменты Facetz',
        isDirectory: true,
        children: [
          {
            id: 3840,
            title: 'Образ жизни',
            isDirectory: true,
            children: [
              {
                id: 2681,
                title: 'Обзоры',
                isDirectory: false
              }
            ]
          }
        ]
      }
    ]
  }
]


Моё решение:
const traverseItems = (acc, currentNode, index, allNodes) => {
  const path = currentNode.name.split('/');
  const title = path[path.length - 1].replace(/("|')/g, '');
  const id = currentNode.id;

  const currentChildren = allNodes
    .filter(n => n.id !== id)
    .filter(n => n.name.includes(title));

  const isDirectory = currentChildren.length > 0 || id === 0;

  if (isDirectory) {
    return acc.concat([{
      id,
      title,
      isDirectory,
      children: currentChildren.reduce(traverseItems, acc)
    }]);
  } else {
    return acc.concat([{ id, title, isDirectory }]);
  }
};

const result = nodes.reduce(traverseItems, []);
  • Вопрос задан
  • 244 просмотра
Подписаться 3 Простой 1 комментарий
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
function getTree(data) {
  let root = data.find(n => n.id === 0);
  root = { title: root.name.slice(1,-1), id: root.id };

  data.filter(n => n.id !== 0).forEach(item => {
    const node = item.name.slice(1, -1).split('/').reduce((parent, title) => {
      if (!parent.children) {
        Object.assign(parent, { children: [], isDirectory: true });
      }
      let child = parent.children.find(m => m.title === title);
      if (!child) {
        child = { title };
        parent.children.push(child);
      }
      return child;
    }, root);
    Object.assign(node, { id: item.id, isDirectory: !!node.isDirectory });
  });

  return root;
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы