Обход структурированных данных древовидного типа с использованием JavaScript

У меня есть набор данных, в котором есть родительские и вложенные дочерние элементы. Целью этих данных является переход от родителя к -> child1 к -> Child1Child..... -> дочерний2 до -> дочерний1 до -> дочерний2 до -> дочерний3 -> ребенок3 -> ребенок4

Как только конец узла будет достигнут, начните движение в обратном направлении от конца узла к началу, например. child2, где другие дети были остановлены и еще не посещались.

Набор данных в отношениях родитель-потомок

[
            {
                "id": 0,
                "children": [
                    {
                        "id": 3,
                        "parentId": 0,
                        "children": [
                            {
                                "id": 6,
                                "parentId": 3,
                                "children": [
                                    {
                                        "id": 11,
                                        "parentId": 6,
                                        "children": [
                                            {
                                                "id": 10,
                                                "parentId": 11,
                                                "children": [
                                                    {
                                                        "id": 8,
                                                        "parentId": 10,
                                                    }
                                                ]
                                            }
                                        ]
                                    },
                                    {
                                        "id": 9,
                                        "parentId": 6,
                                        "children": [
                                            {
                                                "id": 1,
                                                "parentId": 9,
                                                "children": [
                                                    {
                                                        "id": 7,
                                                        "parentId": 1,
                                                    }
                                                ]
                                            }
                                        ]
                                    },
                                    {
                                        "id": 4,
                                        "parentId": 6,
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]



let result = [];
const handleTree = ( tree, count) => {
        count = count || 0
        const tree = _.clone(data);
        if ( tree ){
            tree.forEach( ( t: any, i: string | number ) => {
                let deepCopy = _.clone({...t });
                delete deepCopy.children;
                const { id, parentId } = deepCopy
                result.push({ id, isVisited: true, parentId });
                if ( tree[i].children ){
                    handleTree(tree[i].children, count+1 )
                }else{
                    //Completed start reading backward
                    // const getPreviousParent = findParentDetails(tree[i].parentId )

                }
            })
        }
}

Как подойти к этой проблеме? До сих пор мне удавалось читать данные в том же направлении, но при движении назад я получал неожиданные результаты.

Надеюсь, я хорошо объяснил вопрос и он имеет смысл. Предложения приветствуются.

возможно, вы можете использовать алгоритм поиска в глубину (DFS) для обхода этой древовидной структуры данных, IIRC использует стек и хэш-набор для хранения посещенных и непосещенных узлов для каждой вершины. Я использовал его однажды для решения аналогичной проблемы. Вот Руководство по JS о том, как это сделать. Надеюсь это поможет.

mrSoh 16.07.2024 22:28
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
1
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это очень похоже на поиск в глубину (DFS) с древовидной структурой.

Я думаю, что в отношении направления вперед ваш подход правильный. Для обратного направления вам необходимо поддерживать стек узлов. Если вы достигнете узла без дочерних узлов, вам нужно извлечь его из стека и посетить другие оставшиеся дочерние узлы.

Вы можете сделать что-то вроде этого:

let result = [];
let stack = [];

const handleTree = (tree, count) => {
    count = count || 0;
    if (tree) {
        tree.forEach((t, i) => {
            let deepCopy = {...t};
            delete deepCopy.children;
            const { id, parentId } = deepCopy;
            result.push({ id, isVisited: true, parentId });
            if (t.children) {
                // push current node to stack
                stack.push({node: t, index: i+1});
                // recursively call handleTree for children
                handleTree(t.children, count+1);
            } else {
                // if no children, start backtracking
                while (stack.length > 0) {
                    let top = stack[stack.length - 1]; // peek top of stack
                    if (top.node.children && top.index < top.node.children.length) {
                        // if top node has unvisited children, visit them
                        handleTree([top.node.children[top.index]], count+1);
                        top.index++; // increment index of top node
                    } else {
                        // if no unvisited children, pop from stack
                        stack.pop();
                    }
                }
            }
        });
    }
};

Ответ принят как подходящий

Некоторые комментарии к вашей попытке:

  1. Нет необходимости что-либо клонировать при деструктуризации на примитивы. Кроме того, удаление children из клона не потребуется.
  2. Чтобы предметы также добавлялись на обратном пути, просто сделайте то же самое (то же самое result.push), что и на пути вниз.
  3. Вам не нужен i. Ваша переменная цикла — это нужный вам объект узла.
  4. В вашем коде нет смысла использовать count. Но я добавил его в сгенерированные элементы. Лучше, чтобы счетчик был одним числом, чем отдельной переменной для каждого выполнения, чтобы избежать дублирования. Для этого вы можете обернуть этот единственный счетчик в объект.
  5. Если каждый выходной объект получает свойство visited: true, то он не добавляет никакой полезной информации.

Для такого обхода пригодится генератор: таким образом вы не требуете, чтобы результаты собирались в массиве - вы оставляете на усмотрение вызывающей стороны решать, что делать со значениями и следует ли прерывать обход. .

Вы также можете добавить свойство, указывающее направление (вниз или вверх).

Вот возможная реализация:

// Define a generator
function* handleTree(tree, counter = {node: 0}) {
    for (const node of tree ?? []) {
        // No need to clone when you destructure into primitive values:
        const {id, parentId, children} = node;
        const current = { id, parentId, direction: "down", ...counter };
        counter.node++;
        yield current;
        if (children) {
            yield* handleTree(children, counter);
        }
        yield {...current, direction: "up" }; // change the direction
    }
}

// Your example tree:
const tree = [{"id": 0,"children": [{"id": 3,"parentId": 0,"children": [{"id": 6,"parentId": 3,"children": [{"id": 11,"parentId": 6,"children": [{"id": 10,"parentId": 11,"children": [{"id": 8,"parentId": 10,}]}]},{"id": 9,"parentId": 6,"children": [{"id": 1,"parentId": 9,"children": [{"id": 7,"parentId": 1,}]}]},{"id": 4,"parentId": 6,}]}]}]}];
const result = [...handleTree(tree)]; // Collect into array
console.info(result);

как я могу добавить сюда добавочный идентификатор, который должен увеличиваться при уменьшении. Оно не должно увеличиваться при движении вверх.

vikas dhiman 17.07.2024 09:04

Каким должен быть идентификатор элементов, обозначающих движение вверх?

trincot 17.07.2024 09:09

Идентификатор не в заказе. Я хочу вести здесь учет детей, например. Узел 1, Узел 2, Узел 3 и т. д.

vikas dhiman 17.07.2024 09:14

Вы имеете в виду, что это детский номер? Итак, если у ребенка есть ребенок, должен ли этот ребенок снова получить номер 1? Если нет, то как должна выглядеть нумерация?

trincot 17.07.2024 09:21

Нет, Дочерний элемент 1 -> Узел 1 Дочерний элемент Дочернего элемента 1 -> Узел 2........... Дочерний элемент n -> Узел 3

vikas dhiman 17.07.2024 09:25

И должно ли это регистрироваться в возвращаемом элементе? А как насчет восходящих элементов, какой номер они тогда должны получить?

trincot 17.07.2024 09:28

Правильно, это должно быть зарегистрировано для ребенка во время спуска. Для восходящих элементов это не должно регистрироваться, потому что мы уже добавляем этот инкрементальный счетчик/идентификатор при движении вниз. То же самое должно быть и для нисходящих элементов.

vikas dhiman 17.07.2024 09:30

Извините, я не понимаю. Элементы, расположенные вверх, являются отдельными объектами. Какой номер для них?

trincot 17.07.2024 09:31

Давайте продолжим обсуждение в чате.

vikas dhiman 17.07.2024 09:33

Обновил ответ согласно вашим объяснениям.

trincot 17.07.2024 10:08

Другие вопросы по теме