Создать вложенный массив объектов из массива плоских объектов с помощью childIds - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть плоский массив объектов, который мне нужен в (глубоко) вложенном массиве объектов.

Мой плоский массив (идентификаторы случайны в реальности, но здесь для ясности изменен, и вложение может быть очень глубокий):

const tags = [
  {
    id: 'tag1',
    title: 'Tag 1',
    childIds: ['tag11', 'tag12'],
    root: true
  },
  {
    id: 'tag11',
    title: 'Tag 11',
    childIds: ['tag111', 'tag112'],
  },
  {
    id: 'tag12',
    title: 'Tag 12',
    childIds: ['tag121']
  },
  {
    id: 'tag111',
    title: 'Tag 111',
    childIds: []
  },
  {
    id: 'tag112',
    title: 'Tag 112',
    childIds: []
  },
  {
    id: 'tag121',
    title: 'Tag 121',
    childIds: []
  }
]

Мой желаемый вывод:

tagsNested = [
  {
    id: 'tag1',
    title: 'Tag 1',
    tags: [
      {
        id: 'tag11',
        title: 'tag 11',
        tags: [
          {
            id: 'tag111',
            title: 'Tag 111',
            tags: []
          },
          {
            id: 'tag112',
            title: 'Tag 112',
            tags: []
          }
        ]
      },
      {
        id: 'tag12',
        title: 'tag 12',
        tags: [
          {
            id: 'tag121',
            title: 'Tag 121',
            tags: []
          }
        ]
      }
    ]
  }

]

Пока что я стараюсь вкладывать все теги в любой тег.

Т.е. я делаю получить вложенный массив, но каждый тег-массив содержит все теги .

function unflatten(tag, nestedTags) {
  if (tag.childIds) {
    tag.childIds.forEach((childId) => {
      var childTag = tags.find((t) => t.id === childId)
      childTag.tags = unflatten(childTag, nestedTags)
      nestedTags.push(childTag)
    })
  }
  return nestedTags
}
const rootTag = tags.find((tag) => tag.root)
console.log(unflatten(rootTag, []))

Я действительно борюсь с этими рекурсивными функциями и выясняю, как сделать так, чтобы операторы return дали мне правильные данные.

Ответы [ 4 ]

2 голосов
/ 18 апреля 2020

Вы можете использовать карту для обозначения каждого узла, а затем создать новый формат объекта из этого. Наконец, удалите записи с карты, у которых есть родители, так что root останется. Так что действительно, свойство root не нужно. Это косвенно вытекает из данных отношений. Этот алгоритм не использует это свойство:

const tags = [{id: 'tag1',title: 'Tag 1',childIds: ['tag11', 'tag12'],root: true},{id: 'tag11',title: 'Tag 11',childIds: ['tag111', 'tag112'],},{id: 'tag12',title: 'Tag 12',childIds: ['tag121']},{id: 'tag111',title: 'Tag 111',childIds: []},{id: 'tag112',title: 'Tag 112',childIds: []},{id: 'tag121',title: 'Tag 121',childIds: []}];

let map = new Map(tags.map(({id, title, childIds}) => [id, { id, title, tags: [] }]));
tags.forEach(tag => map.get(tag.id).tags = tag.childIds.map(id => map.get(id)));
tags.forEach(tag => tag.childIds.forEach(id => map.delete(id)));
let tagsNested = [...map.values()];
console.log(tagsNested);
2 голосов
/ 18 апреля 2020

Это рекурсивный подход. Это работает так:

  1. С учетом тега root (или любого тега) и tagsArray (сглаживание массива тегов)
  2. Фильтрация всех дочерних тегов root
  3. Затем для каждого дочернего элемента найдите все его дочерние теги
  4. Затем верните тег, если дочерних тегов больше нет

Вы можете попробовать этот фрагмент кода:

const tags = [
  {
    id: 'tag1',
    title: 'Tag 1',
    childIds: ['tag11', 'tag12'],
    root: true
  },
  {
    id: 'tag11',
    title: 'Tag 11',
    childIds: ['tag111', 'tag112'],
  },
  {
    id: 'tag12',
    title: 'Tag 12',
    childIds: ['tag121']
  },
  {
    id: 'tag111',
    title: 'Tag 111',
    childIds: []
  },
  {
    id: 'tag112',
    title: 'Tag 112',
    childIds: []
  },
  {
    id: 'tag121',
    title: 'Tag 121',
    childIds: []
  }
]

function buildTag({id, title, childIds}, tagsArray) {
  const tags = tagsArray
    .filter(tag => childIds.includes(tag.id))
    .map(tag => buildTag(tag, tagsArray))

  return {
      id,
      title,
      tags,
    }
}

const rootTag = tags.find((tag) => tag.root)
console.log([buildTag(rootTag, tags)])

/* 
tagsNested = [
  {
    id: 'tag1',
    title: 'Tag 1',
    tags: [
      {
        id: 'tag11',
        title: 'tag 11',
        tags: [
          {
            id: 'tag111',
            title: 'Tag 111',
            tags: []
          },
          {
            id: 'tag112',
            title: 'Tag 112',
            tags: []
          }
        ]
      },
      {
        id: 'tag12',
        title: 'tag 12',
        tags: [
          {
            id: 'tag121',
            title: 'Tag 121',
            tags: []
          }
        ]
      }
    ]
  }
]
*/
1 голос
/ 18 апреля 2020

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

const tags = [{ id: 'tag1', title: 'Tag 1', childIds: ['tag11', 'tag12'], root: true }, { id: 'tag11', title: 'Tag 11', childIds: ['tag111', 'tag112'] }, { id: 'tag12', title: 'Tag 12', childIds: ['tag121'] }, { id: 'tag111', title: 'Tag 111', childIds: [] }, { id: 'tag112', title: 'Tag 112', childIds: [] }, { id: 'tag121', title: 'Tag 121', childIds: [] }],
    tree = function (array) {
        var t = {},
            tree = [];

        array.forEach(({ id, title, childIds, root }) => {
            Object.assign(
                t[id] = t[id] || {},
                { id, title, tags: childIds.map(id => t[id] = t[id] || { id }) }
            );
            if (root) tree.push(t[id]);
        });

        return tree;
    }(tags);

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 18 апреля 2020

Вот кодовые окна - https://codesandbox.io/s/green-dawn-3gpvz?file= / src / index. js. Единственная разница с вашим требованием - результат - это просто объект, а не массив, но вы можете просто обернуть этот единственный элемент в массив

function resolveChildren(tag, allTags) {
  const { childIds, root, ...rest } = tag;
  if (!childIds) return rest;

  return {
    ...rest,
    tags: childIds.map(childId =>
      resolveChildren(allTags.find(t => t.id === childId), allTags)
    )
  };
}

resolveChildren(tags.find(tag => !!tag.root), tags)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...