按后代和祖先将列表转换为树

Convert list to tree by descendants and ancestors

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

我有这样的例子:

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

我们非常欢迎任何建议。

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

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

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

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