Tengo un archivo json complejo que tengo que manejar con javascript para hacerlo jerárquico, para luego construir un árbol. Cada entrada de json tiene: id: un id único, parentId: el id del nodo padre (que es 0 si el nodo es una raíz del árbol) nivel: el nivel de profundidad en el árbol
Los datos json ya están "ordenados". Quiero decir que una entrada tendrá sobre sí mismo un nodo padre o hermano, y debajo de sí mismo un nodo hijo o un nodo hermano.
Entrada:
{
"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
},
]
}
Rendimiento esperado :
{
"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
fuente
fuente
parentId
de0
significa que no hay identificación principal y debería ser la capa superior.Respuestas:
Hay una solución eficiente si usa una búsqueda de mapas. Si los padres siempre vienen antes que sus hijos, puede fusionar los dos bucles for. Es compatible con múltiples raíces. Da un error en las ramas colgantes, pero puede modificarse para ignorarlas. No requiere una biblioteca de terceros. Es, por lo que puedo decir, la solución más rápida.
Si te gusta la teoría de la complejidad, esta solución es Θ (n log (n)). La solución de filtro recursivo es Θ (n ^ 2), lo que puede ser un problema para grandes conjuntos de datos.
fuente
map
que (en teoría) es O (log n).Como mencionó @Sander, la respuesta de @ Halcyon supone una matriz ordenada previamente, lo siguiente no. (Sin embargo, asume que ha cargado underscore.js, aunque podría estar escrito en JavaScript de vainilla):
Código
Requisitos
Asume que las propiedades 'id' y 'parentid' indican ID e ID padre respectivamente. Debe haber elementos con ID padre 0, de lo contrario, obtendrá una matriz vacía. Los elementos huérfanos y sus descendientes están 'perdidos'
http://jsfiddle.net/LkkwH/1/
fuente
else { parent['children'] = []; }
después de la primera cláusula if para asegurarse de que cada nodo tenga un atributochildren
(estará vacío si el nodo es un nodo hoja)tree
nunca se pasa como argumento cuando se llama a la función de forma recursiva, por lo que creo que la líneatree = typeof tree !== 'undefined' ? tree : [];
se puede reemplazar porlet tree = [];
null
parent_ids en lugar de 0? Editar: No importa, lo hice funcionar cambiando elid: 0
aid: null
.(BONUS1: NODOS PUEDEN O NO PEDIRSE)
(BONUS2: NO SE NECESITA BIBLIOTECA DE TERCEROS, LISO JS)
(BONUS3: El usuario "Elias Rabl" dice que esta es la solución más rápida, vea su respuesta a continuación)
Aquí está:
Aquí hay una prueba, podría ayudarlo a comprender cómo funciona la solución:
fuente
childNodes
solo cuando sea necesario? ¿Quitándolos del primeroforEach
y moviéndolos dentro del segundo?Tuve el mismo problema, pero no podía estar seguro de que los datos estuvieran ordenados o no . No pude usar una biblioteca de terceros, así que esto es solo vanilla Js; Los datos de entrada pueden tomarse del ejemplo de @ Stephen;
JS Fiddle
Matriz plana al árbol
fuente
mappedArr[mappedElem['parentid']]['children']
estaba fallando ya que no se puede acceder achildren
indefinido.Use este enfoque ES6. Funciona como encanto
fuente
una función más simple list-to-tree-lite
npm install list-to-tree-lite
listToTree(list)
fuente:
jsfiddle
fuente
Puede manejar esta pregunta con solo dos líneas de codificación:
Prueba en línea (consulte la consola del navegador para ver el árbol creado)
Requisitos:
1- Instala lodash 4 (una biblioteca de Javascript para manipular objetos y colecciones con métodos de rendimiento => como Linq en c #) Lodash
2- Una matriz plana como a continuación:
Gracias Sr. Bakhshabadi
Buena suerte
fuente
Puede ser útil el paquete list-to-tree Instalar:
o
Por ejemplo, tener lista:
Use el paquete list-to-tree:
Resultado:
fuente
He escrito un script de prueba para evaluar el rendimiento de las dos soluciones más generales (lo que significa que la entrada no tiene que clasificarse de antemano y que el código no depende de bibliotecas de terceros), propuesta por los usuarios shekhardtu ( ver respuesta ) y FurkanO ( ver respuesta ).
http://playcode.io/316025?tabs=console&script.js&output
La solución de FurkanO parece ser la más rápida.
fuente
Esta es una propuesta para artículos no ordenados. Esta función funciona con un solo bucle y con una tabla hash y recopila todos los elementos con sus
id
. Si se encuentra un nodo raíz, el objeto se agrega a la matriz de resultados.fuente
también hazlo con lodashjs (v4.x)
fuente
Me gusta la solución de JavaScript puro de @ WilliamLeung, pero a veces es necesario realizar cambios en la matriz existente para mantener una referencia al objeto.
Exapmle: https://jsfiddle.net/kqw1qsf0/17/
fuente
fuente
Es posible que eche un vistazo al paquete npm tree-util. También puede ser muy útil si desea cargar datos de una tabla de datos SQL DB. También puede agregar fácilmente datos adicionales a los nodos en el árbol creado.
Descargo de responsabilidad, hice este paquete.
fuente
Tuve un problema similar hace un par de días cuando tuve que mostrar el árbol de carpetas desde una matriz plana. No vi ninguna solución en TypeScript aquí, así que espero que sea útil.
En mis casos, el padre principal era solo uno, también la matriz rawData no tiene que ser ordenada. Las soluciones se basan en preparar objetos temporales como
{parentId: [child1, child2, ...] }
ejemplo de datos en bruto
def de carpeta
SOLUCIÓN : Función que devuelve la estructura de árbol para argumento plano
fuente
Aquí hay una función auxiliar simple que creé siguiendo el modelo de las respuestas anteriores, adaptada a un entorno Babel:
fuente
Aquí hay una versión modificada de Steven Harris que es simple ES5 y devuelve un objeto con clave en la identificación en lugar de devolver una matriz de nodos tanto en el nivel superior como para los niños.
fuente
Esta es una versión modificada de lo anterior que funciona con varios elementos raíz, utilizo GUID para mis identificadores y parentIds, así que en la interfaz de usuario que los crea codifico los elementos raíz para algo como 0000000-00000-00000-TREE-ROOT-ITEM
var tree = unflatten (registros, "TREE-ROOT-ITEM");
fuente
Copiado de Internet http://jsfiddle.net/stywell/k9x2a3g6/
fuente
Puede usar el paquete npm array-to-tree https://github.com/alferov/array-to-tree . Convierte una matriz simple de nodos (con punteros a nodos principales) en una estructura de datos anidada.
Resuelve un problema con la conversión de conjuntos de datos recuperados de una base de datos a una estructura de datos anidados (es decir, árbol de navegación).
Uso:
fuente
esto es lo que usé en un proyecto de reacción
uso:
salida:
fuente
Puede usar este paquete "treeify" de Github aquí o NPM .
Instalación:
$ npm install --save-dev treeify-js
fuente
Mi solución mecanografiada, tal vez te ayude:
Ejemplo de uso:
fuente
Escribí una versión ES6 basada en la respuesta @Halcyon
El principio de este algoritmo es usar "mapa" para establecer una relación de índice. Es fácil encontrar "elemento" en la lista por "parentId" y agregar "elementos secundarios" a cada "elemento", porque "lista" es una relación de referencia, por lo que "raíces" creará relaciones con todo el árbol.
fuente
Responda a una pregunta similar:
https://stackoverflow.com/a/61575152/7388356
ACTUALIZAR
Puede usar el
Map
objeto introducido en ES6. Básicamente, en lugar de encontrar padres al iterar sobre la matriz nuevamente, solo obtendrá el elemento primario de la matriz por la identificación de los padres como si obtuviera elementos en una matriz por índice.Aquí está el ejemplo simple:
fuente
Basado en la respuesta de @ FurkanO , creé otra versión que no muta los datos originales (como solicitó @ Dac0d3r). Realmente me gustó la respuesta de @ shekhardtu , pero me di cuenta de que tenía que filtrar los datos muchas veces. Pensé que una solución podría ser usar la respuesta de FurkanO copiando primero los datos. Probé mi versión en jsperf , y los resultados fueron lamentablemente (muy) sombríos ... ¡Parece que la respuesta aceptada es realmente buena! Sin embargo, mi versión es bastante configurable y segura, así que la comparto con ustedes de todos modos; Aquí está mi contribución:
Con el parámetro de opciones, es posible configurar qué propiedad usar como ID o ID principal. También es posible configurar el nombre de la propiedad secundaria, si alguien quiere
"childNodes": []
o algo.OP simplemente podría usar las opciones predeterminadas:
Si el ID de padre es (Falsy
null
,undefined
los valores Falsy u otros) o no existe el objeto padre, consideramos que el objeto a ser un nodo raíz.fuente
Prueba esto
Pruébalo en Jsfiddle
fuente
Convertir matriz de nodos a árbol
Función ES6 para convertir una matriz de nodos (relacionados por ID principal ) - a una estructura de árbol:
Generar lista HTML desde el árbol de nodos
Teniendo nuestro árbol en su lugar, aquí hay una función recursiva para construir los elementos UL> LI:
Tiempo de demostración
Aquí hay un ejemplo que tiene una matriz lineal de nodos y usa ambas funciones anteriores:
fuente
Este es un hilo viejo pero pensé que una actualización nunca está de más, con ES6 puedes hacer:
espero que ayude a alguien
fuente