【问题标题】:Convert list to tree by descendants and ancestors按后代和祖先将列表转换为树
【发布时间】:2021-04-15 14:22:48
【问题描述】:

我正在尝试使用元素中的后代和祖先参数将列表转换为树:

例如,我有这样的事情:

const itemToUpdate = {
  id: 1,
  ancestors: [
    {
      id: 2,
      ancestors: [
        {
          id: 4
        }
      ]
    }
  ],
  descendants: [
    {
      id: 3,
      descendants: [
        {
          id: 5
        },
        {
          id: 6,
          descendants: [
            {
              id: 8
            },
            {
              id: 9
            }
          ]
        },
        {
          id: 7
        }
      ]
    }
  ]
};

const updatedItem = {
  id: 4,
  children: [
    {
      id: 2,
      children: [
        {
          id: 1,
          children: [
            {
              id: 3,
              children: [
                {
                  id: 5
                },
                {
                  id: 6,
                  children: [
                    {
                      id: 8
                    },
                    {
                      id: 9
                    }
                  ]
                },
                {
                  id: 7
                }
              ]
            }
          ]
        }
      ]
    }
  ]
};

关键是树可以嵌套很多层。此外,关卡上可能有很多祖先和后代,所以我需要一个更通用的解决方案。树必须从祖先向上创建,从后代向下创建。

我找到了一种获取树的后代的方法,但我仍然需要在这棵树的顶部添加祖先:

export const convertListToTree = <T extends ApiTree<T>>(list: Array<T>, key = 'ascendants'): Array<T> => {
  const getNestedItem = (path: Array<string>, tree: Array<T>): T => {
    const nestedItem = tree.find(nestedItem => nestedItem.id === path[0]);
    const newPath = path.slice(1);
    if (!newPath.length) {
      return nestedItem;
    } else if (nestedItem?.[key]) {
      return getNestedItem(newPath, nestedItem?.[key]);
    } else {
      return getNestedItem(newPath, tree);
    }
  };

  const sortListByPathLength = (list: Array<T>): Array<T> => {
    return sortBy(list, (item: T) => item.path?.length);
  };

  const addRootItem = (item: T, tree: Array<T>): void => {
    tree.push(item);
  };

  const addChildrenItem = (item: T, tree: Array<T>): void => {
    const parent = getNestedItem(item.path, tree);
    if (parent) {
      parent[key].push(item);
    } else {
      addRootItem(item, tree);
    }
  };

  const tree = [];
  if (list?.length) {
    const sortedList = sortListByPathLength(list);
    sortedList.forEach(item => {
      if (!item.path?.length) {
        addRootItem(item, tree);
      } else {
        addChildrenItem(item, tree);
      }
    });
  }
  return tree;
};

任何建议都将受到欢迎。 ????

【问题讨论】:

  • 如果您有多个项目怎么办?你试过什么?
  • 抱歉,如果一个节点有多个祖先,应该怎么办?这对解决方案非常重要。
  • @NinaScholz 嗯,这是个好问题。我认为我们应该将一个或多个根级别降低,例如在这篇文章中:shareablecode.com/snippets/…
  • 我不清楚多个祖先会发生什么?那么这棵树的根是什么?据我了解,在这种情况下没有树,而是有向无环图。请编辑您的问题并举例说明此类输入和预期输出。
  • @NinaScholz 你完全正确,对不起.. 每个节点可以有多个后代,但只有一个祖先。我用这种情况更新了这个例子。很抱歉造成混乱

标签: javascript typescript recursion tree traversal


【解决方案1】:

假设每个级别只有一个祖先,您可以采用递归函数来保留子节点但返回最早的祖先节点。

const
    fn = ({ id, ancestors, descendants }, children) => {
        const node = { id };
        if (Array.isArray(children)) node.children = children;
        if (descendants) node.children = descendants.map(fn);
        return ancestors
            ? fn(ancestors[0], [node])
            : node;
    },
    data = { id: 1, ancestors: [{ id: 2, ancestors: [{ id: 4 }] }], descendants: [{ id: 3, descendants: [{ id: 5 }] }] },
    result = fn(data);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

  • 哇,酷。我们必须假设每个级别可能有几个后代和祖先。但这就是?
【解决方案2】:

我不太确定你想在那里实现什么。能再详细一点吗?
如果有帮助,这就是您转换特定示例的方式。

function convert(item) {
  return {
    id: item.ancestors[0].id,
    children: [
      {
        id: item.id,
        children: [
          {
            id: item.descendants[0].id
          }
        ]
      }      
    ]
  }
}

【讨论】:

  • 重点是树可以嵌套很多层。此外,关卡上可能有很多祖先和后代,所以我需要一个更通用的解决方案。树必须从祖先向上创建,从后代向下创建。
  • @Patryk,您可以将此案例添加到问题中。
  • @Patryk 你能举个例子,数组中有更多项目吗?我不确定你想如何处理分配可能很棘手的 id
猜你喜欢
  • 2016-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多