Найдите путь к узлу во вложенном объекте дерева

#javascript #typescript

Вопрос:

Я создал функцию, которая генерирует путь к целевому узлу из корня дерева. Но есть небольшая ошибка, на которой я застрял.

Реализация:

 interface FSNode {
    name: string;
    id: string;
    type: 'file' | 'dir';
    isPlaceholder?: boolean;
    showIcons: boolean;
    ext?: string;
    children?: FSNode[];
}

const getFSNodePath = (tree: Array<FSNode>, targetNode: FSNode) => {
    let currentPath = '';
    
    function buildPath(subTree: Array<FSNode>, targetNode: FSNode): string | undefined{
        for(const node of subTree){
            // loop all and find if the node matches the target 
            if(node.id === targetNode.id){
                // add the targetn node to path end
                currentPath = currentPath   '/'   node.name;
                return currentPath;
            } else if(node.children){
                // if it doesn't match, check if it has children
                // if children present, check the node in them ( recursion )
                // before checking the children, add the node name to path ( to build the path name )
                currentPath = currentPath   '/'   node.name;

                const path = buildPath(node.children, targetNode);
                // only return(stop) the fn when there is any path ( coming from above case node.id === targetNode.id );
                // if there is no path, means it couldn't find any thing, don't return ( stop ) because need to check the children
                // of other nodes as well and if we return the loop will also stop.
                if(path) return path;
            }
        }
    }

    const path = buildPath(tree, targetNode);

    return path;
};
 

Жук:

  • Src
    • app.js
  • Компоненты
  • index.html

если я хочу найти путь для index.html, код сначала проходит через первые два корневых узла. Сначала он проверяет папку src, а затем ее дочерние элементы. Если он не находит целевой узел в своих дочерних узлах, код проверяет второй корневой узел и, в конечном счете, третий и возвращает путь. Но он возвращает неправильный путь примерно так — /src/index.html вместо /index.html этого .

Возможным решением этой проблемы было бы сбросить currentPath переменную в пустые строки после того, как мы выйдем из вложенных папок. Но я не могу понять, где я должен сбросить переменную currentPath.

Комментарии:

1. передайте currentPath как параметр и попробуйте. buildPath(tree, targetNode, currentPath)

2. Мне жаль, но я не понимаю, что произойдет при прохождении текущего пути.

Ответ №1:

Каждый вызов вашей buildPath функции изменяет одно и то же currentPath , поэтому "/src" прикрепляется при входе в первое поддерево и не удаляется при выходе из него.

Чтобы избежать этого, сделайте путь аргументом buildPath :

 const getFSNodePath = (root: FSNode, targetNode: FSNode): string => {

  /**
   * returns the path as an array of tree nodes, from `root` to `targetNode`
   * or `null` if no child under the `path` matches the targetNode
   */
  const buildPath = (currentPath: FsNode[], targetNode: FSNode): FSNode[] | null => {
    const currentNode = currentPath[currentPath.length - 1];
    if (currentNode.id === targetNode.id) return currentPath;
    
    for (const child of currentNode.children ?? []) {
      const pathFound = buildPath(currentPath.concat(child), targetNode);
      if (pathFound) return pathFound;
    }
    return null;
  }

  const path = findPath([rootNode], targetNode) ?? []
  return path.reduce((joined, node) => `${joined}/${node.name}`, '')
}

 

Ответ №2:

Подсказка @Naren сработала. Передавая путь функции buildPath, она сбрасывает путь при возврате функции.

 const getFSNodePath = (tree: Array<FSNode>, targetNode: FSNode) => {
    function buildPath(subTree: Array<FSNode>, targetNode: FSNode, currentPath: string): string | undefined{
        for(const node of subTree){
            // loop all and find if the node matches the target 
            if(node.id === targetNode.id){
                // add the targetn node to path end
                return currentPath   '/'   node.name;
            } else if(node.children){
                // if it doesn't match, check if it has children
                // if children present, check the node in them ( recursion )
                // before checking the children, add the node name to path ( to build the path name )
                const path = buildPath(node.children, targetNode, currentPath   '/'   node.name);
                // only return(stop) the fn when there is any path ( coming from above case node.id === targetNode.id );
                // if there is no path, means it couldn't find any thing, don't return ( stop ) because need to check the children
                // of other nodes as well and if we return the loop will also stop.
                if(path) return path;
            }
        }
    }

    const path = buildPath(tree, targetNode, '');

    return path;
};