У меня есть сложный файл json, который мне нужно обработать с помощью javascript, чтобы сделать его иерархическим, чтобы позже построить дерево. Каждая запись json имеет: id: уникальный идентификатор, parentId: идентификатор родительского узла (который равен 0, если узел является корнем дерева) уровень: уровень глубины в дереве
Данные json уже «заказаны». Я имею в виду, что запись будет иметь над собой родительский узел или узел-брат, а под собой дочерний узел или узел-брат.
Вход:
{
"People": [
{
"id": "12",
"parentId": "0",
"text": "Man",
"level": "1",
"children": null
},
{
"id": "6",
"parentId": "12",
"text": "Boy",
"level": "2",
"children": null
},
{
"id": "7",
"parentId": "12",
"text": "Other",
"level": "2",
"children": null
},
{
"id": "9",
"parentId": "0",
"text": "Woman",
"level": "1",
"children": null
},
{
"id": "11",
"parentId": "9",
"text": "Girl",
"level": "2",
"children": null
}
],
"Animals": [
{
"id": "5",
"parentId": "0",
"text": "Dog",
"level": "1",
"children": null
},
{
"id": "8",
"parentId": "5",
"text": "Puppy",
"level": "2",
"children": null
},
{
"id": "10",
"parentId": "13",
"text": "Cat",
"level": "1",
"children": null
},
{
"id": "14",
"parentId": "13",
"text": "Kitten",
"level": "2",
"children": null
},
]
}
Ожидаемый результат:
{
"People": [
{
"id": "12",
"parentId": "0",
"text": "Man",
"level": "1",
"children": [
{
"id": "6",
"parentId": "12",
"text": "Boy",
"level": "2",
"children": null
},
{
"id": "7",
"parentId": "12",
"text": "Other",
"level": "2",
"children": null
}
]
},
{
"id": "9",
"parentId": "0",
"text": "Woman",
"level": "1",
"children":
{
"id": "11",
"parentId": "9",
"text": "Girl",
"level": "2",
"children": null
}
}
],
"Animals": [
{
"id": "5",
"parentId": "0",
"text": "Dog",
"level": "1",
"children":
{
"id": "8",
"parentId": "5",
"text": "Puppy",
"level": "2",
"children": null
}
},
{
"id": "10",
"parentId": "13",
"text": "Cat",
"level": "1",
"children":
{
"id": "14",
"parentId": "13",
"text": "Kitten",
"level": "2",
"children": null
}
}
]
}
javascript
arrays
list
tree
Franck
источник
источник
parentId
of0
означает отсутствие родительского идентификатора и должен быть верхним слоем.Ответы:
Есть эффективное решение, если вы используете поиск по карте. Если родители всегда приходят раньше своих детей, вы можете объединить два цикла for. Он поддерживает несколько корней. Он выдает ошибку в зависших ветвях, но может быть изменен, чтобы игнорировать их. Не требует сторонней библиотеки. Насколько я могу судить, это самое быстрое решение.
Если вы занимаетесь теорией сложности, это решение (n log (n)). Решение с рекурсивным фильтром - Θ (n ^ 2), что может быть проблемой для больших наборов данных.
источник
map
котором (теоретически) O (log n).Как упоминалось @Sander, ответ @ Halcyon предполагает предварительно отсортированный массив, а следующее - нет. (Однако предполагается, что вы загрузили файл underscore.js, хотя он может быть написан на ванильном javascript):
Код
Требования
Предполагается, что свойства id и parentid указывают ID и родительский ID соответственно. Должны быть элементы с родительским ID 0, иначе вы получите пустой массив. Осиротевшие элементы и их потомки «потеряны»
http://jsfiddle.net/LkkwH/1/
источник
else { parent['children'] = []; }
после первого предложения if, чтобы гарантировать, что каждый узел имеет атрибутchildren
(он будет пустым, если узел является листовым узлом)tree
никогда не передается в качестве аргумента при рекурсивном вызове функции, поэтому я думаю, что строкуtree = typeof tree !== 'undefined' ? tree : [];
можно заменить наlet tree = [];
null
parent_ids вместо 0? Edit: Nevermind, я получил это работает, изменяяid: 0
кid: null
.(БОНУС 1: УЗЛЫ МОГУТ БЫТЬ ЗАКАЗАНЫ)
(БОНУС 2: НЕ ТРЕБУЕТСЯ ТРЕТЬЯ БИБЛИОТЕКА, PLAIN JS)
(БОНУС 3: пользователь «Элиас Рабл» говорит, что это самое быстрое решение, см. Его ответ ниже)
Вот:
Вот тест, который может помочь вам понять, как работает решение:
источник
childNodes
только тогда, когда это необходимо? Удалив их из первогоforEach
и переместив внутрь второго?Была та же проблема, но я не мог быть уверен, что данные были отсортированы или нет . Я не мог использовать стороннюю библиотеку, так что это просто ванильный Js; Входные данные можно взять из примера @ Stephen;
JS Fiddle
Плоский массив в дерево
источник
mappedArr[mappedElem['parentid']]['children']
не удалось получить доступ кchildren
undefined.Используйте этот подход ES6. Работает как шарм
источник
более простая функция list-to-tree-lite
npm install list-to-tree-lite
listToTree(list)
источник:
jsfiddle
источник
Вы можете решить этот вопрос с помощью всего двухстрочного кодирования:
Протестируйте онлайн (см. Созданное дерево в консоли браузера)
Требования:
1- Установите lodash 4 (библиотека Javascript для управления объектами и коллекциями с помощью эффективных методов => как Linq в C #) Lodash
2- FlatArray, как показано ниже:
Спасибо господину Бахшабади
Удачи
источник
Может пригодиться установка списка пакетов в дерево :
или
Например, есть список:
Использовать список пакетов в дереве:
Результат:
источник
Я написал тестовый сценарий для оценки производительности двух наиболее общих решений (это означает, что ввод не нужно предварительно сортировать и что код не зависит от сторонних библиотек), предложенных пользователями shekhardtu ( см. Ответ ) и FurkanO ( см. ответ ).
http://playcode.io/316025?tabs=console&script.js&output
Решение FurkanO кажется самым быстрым.
источник
Это предложение для неупорядоченных товаров. Эта функция работает с одним циклом и с хеш-таблицей и собирает все элементы с их
id
. Если корневой узел найден, то объект добавляется в массив результатов.источник
также сделайте это с lodashjs (v4.x)
источник
Мне нравится решение @ WilliamLeung на чистом JavaScript, но иногда вам нужно внести изменения в существующий массив, чтобы сохранить ссылку на объект.
Пример: https://jsfiddle.net/kqw1qsf0/17/
источник
источник
У меня была аналогичная проблема пару дней назад, когда мне приходилось отображать дерево папок из плоского массива. Я не видел здесь никакого решения в TypeScript, поэтому надеюсь, что это будет полезно.
В моих случаях основной родитель был только один, также массив rawData не нуждался в сортировке. Решения основаны на подготовке объекта temp, например
{parentId: [child1, child2, ...] }
пример сырых данных
def из папки
РЕШЕНИЕ : функция, которая возвращает древовидную структуру для плоского аргумента
источник
Вот простая вспомогательная функция, которую я создал по образцу приведенных выше ответов, адаптированный к среде Babel:
источник
Вот модифицированная версия Стивена Харриса, которая представляет собой простой ES5 и возвращает объект с ключом по идентификатору, а не возвращает массив узлов как на верхнем уровне, так и для дочерних элементов.
источник
Это модифицированная версия вышеупомянутого, которая работает с несколькими корневыми элементами, я использую GUID для своих идентификаторов и parentIds, поэтому в пользовательском интерфейсе, который их создает, я жестко запрограммировал корневые элементы на что-то вроде 0000000-00000-00000-TREE-ROOT-ITEM
var tree = unflatten (записи, "ДЕРЕВО-КОРНИ-ПУНКТ");
источник
Скопировано из Интернета http://jsfiddle.net/stywell/k9x2a3g6/
источник
Вы можете использовать npm package array-to-tree https://github.com/alferov/array-to-tree . Он преобразует простой массив узлов (с указателями на родительские узлы) во вложенную структуру данных.
Решает проблему с преобразованием извлеченных из базы данных наборов данных во вложенную структуру данных (например, дерево навигации).
Использование:
источник
это то, что я использовал в проекте React
использование:
вывод:
источник
Вы можете использовать этот пакет "treeify" из Github здесь или NPM .
Монтаж:
$ npm install --save-dev treeify-js
источник
Мое машинописное решение, возможно, оно вам поможет:
Пример использования:
источник
Я написал версию ES6 на основе ответа @Halcyon
Принцип этого алгоритма заключается в использовании «карты» для установления отношения индекса. Легко найти «элемент» в списке по «parentId» и добавить «потомков» к каждому «элементу», потому что «список» является ссылочным отношением, поэтому «корни» будут строить отношения со всем деревом.
источник
Ответьте на аналогичный вопрос:
https://stackoverflow.com/a/61575152/7388356
ОБНОВИТЬ
Вы можете использовать
Map
объект, представленный в ES6. По сути, вместо того, чтобы искать родителей путем повторной итерации по массиву, вы просто получаете родительский элемент из массива по родительскому идентификатору, как вы получаете элементы в массиве по индексу.Вот простой пример:
источник
Основываясь на ответе @FurkanO , я создал другую версию, которая не изменяет исходные данные (например, запрос @ Dac0d3r). Мне очень понравился ответ @ shekhardtu , но я понял, что ему нужно много раз фильтровать данные. Я подумал, что решением может быть использование ответа FurkanO, сначала скопировав данные. Я попробовал свою версию в jsperf , и результаты были, к сожалению, (очень) мрачными ... Похоже, что принятый ответ действительно хороший! Моя версия довольно настраиваемая и отказоустойчивая, так что я все равно поделюсь ею с вами, ребята; вот мой вклад:
С помощью параметра options можно настроить, какое свойство использовать в качестве идентификатора или родительского идентификатора. Также есть возможность настроить имя дочернего свойства, если кому-
"childNodes": []
то что-то нужно .OP может просто использовать параметры по умолчанию:
Если родительский идентификатор falsy (
null
,undefined
или другие falsy значения) или родительский объект не существует, мы считаем , что объект будет корневой узел.источник
Попробуй это
Протестируйте на Jsfiddle
источник
Преобразование массива узлов в дерево
Функция ES6 для преобразования массива узлов (связанных родительским идентификатором ) в древовидную структуру:
Создать список HTML из дерева узлов
Имея наше дерево на месте, вот рекурсивная функция для создания элементов UL> LI:
Демонстрационное время
Вот пример с линейным массивом узлов и использованием обеих вышеуказанных функций:
источник
Это старый поток, но я подумал, что обновление никогда не повредит, с ES6 вы можете:
надеюсь, это поможет кому-то
источник