【问题标题】:Create a nested array of objects from flat object array with childIds从具有 childIds 的平面对象数组创建嵌套的对象数组
【发布时间】:2020-08-01 08:44:38
【问题描述】:

我有一个平面对象数组,我需要一个(深度)嵌套的对象数组。

我的平面数组(ID 在现实中是随机的,但为了清楚起见在这里更改了,嵌套可能很深):

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 语句为我提供正确的数据。

【问题讨论】:

    标签: javascript arrays json recursion data-structures


    【解决方案1】:

    这是一个代码框 - 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)
    

    【讨论】:

    • 请在您的答案中包含代码。外部链接也可以,特别是如果它可以提供更多上下文,但相关代码应该始终在此处可用。
    【解决方案2】:

    这是一种递归方法。它是这样工作的:

    1. 给定root 标签(或任何标签)和tagsArray(扁平标签数组)
    2. 过滤root的所有子标签
    3. 然后为每个孩子找到它的所有孩子标签
    4. 然后在没有子标签时返回标签

    你可以试试这个代码 sn-p:

    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: []
              }
            ]
          }
        ]
      }
    ]
    */

    【讨论】:

    • 这可行,但效率不高。它的时间复杂度为 O(n²),而时间复杂度为 O(n)。
    【解决方案3】:

    您可以采用迭代方法,将对象作为对节点的引用。

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

    【讨论】:

      【解决方案4】:

      您可以使用 Map 来设置每个节点的键,然后从中创建新的对象格式。最后从地图中删除具有父项的条目,以便根保留。所以真的,不需要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);

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-06
        • 2021-08-02
        • 1970-01-01
        • 2021-11-28
        • 2021-07-04
        • 1970-01-01
        相关资源
        最近更新 更多