Esto requiere una función recursiva muy básica para analizar los pares hijo / padre en una estructura de árbol y otra función recursiva para imprimirla. Solo una función sería suficiente, pero aquí hay dos para mayor claridad (se puede encontrar una función combinada al final de esta respuesta).
Primero inicialice la matriz de pares hijo / padre:
$tree = array(
'H' => 'G',
'F' => 'G',
'G' => 'D',
'E' => 'D',
'A' => 'E',
'B' => 'C',
'C' => 'E',
'D' => null
);
Luego, la función que analiza esa matriz en una estructura de árbol jerárquica:
function parseTree($tree, $root = null) {
$return = array();
# Traverse the tree and search for direct children of the root
foreach($tree as $child => $parent) {
# A direct child is found
if($parent == $root) {
# Remove item from tree (we don't need to traverse this again)
unset($tree[$child]);
# Append the child into result array and parse its children
$return[] = array(
'name' => $child,
'children' => parseTree($tree, $child)
);
}
}
return empty($return) ? null : $return;
}
Y una función que atraviesa ese árbol para imprimir una lista desordenada:
function printTree($tree) {
if(!is_null($tree) && count($tree) > 0) {
echo '<ul>';
foreach($tree as $node) {
echo '<li>'.$node['name'];
printTree($node['children']);
echo '</li>';
}
echo '</ul>';
}
}
Y el uso real:
$result = parseTree($tree);
printTree($result);
Aquí está el contenido de $result:
Array(
[0] => Array(
[name] => D
[children] => Array(
[0] => Array(
[name] => G
[children] => Array(
[0] => Array(
[name] => H
[children] => NULL
)
[1] => Array(
[name] => F
[children] => NULL
)
)
)
[1] => Array(
[name] => E
[children] => Array(
[0] => Array(
[name] => A
[children] => NULL
)
[1] => Array(
[name] => C
[children] => Array(
[0] => Array(
[name] => B
[children] => NULL
)
)
)
)
)
)
)
)
Si desea un poco más de eficiencia, puede combinar esas funciones en una y reducir la cantidad de iteraciones realizadas:
function parseAndPrintTree($root, $tree) {
$return = array();
if(!is_null($tree) && count($tree) > 0) {
echo '<ul>';
foreach($tree as $child => $parent) {
if($parent == $root) {
unset($tree[$child]);
echo '<li>'.$child;
parseAndPrintTree($child, $tree);
echo '</li>';
}
}
echo '</ul>';
}
}
Solo guardará 8 iteraciones en un conjunto de datos tan pequeño como este, pero en conjuntos más grandes podría marcar la diferencia.
Otra función más para hacer un árbol (sin recursividad involucrada, usa referencias en su lugar):
Devuelve una matriz jerárquica como esta:
Que se puede imprimir fácilmente como una lista HTML utilizando la función recursiva.
fuente
Otra forma más simplificada de convertir la estructura plana
$treeen una jerarquía. Solo se necesita una matriz temporal para exponerlo:Eso es todo para colocar la jerarquía en una matriz multidimensional:
El resultado es menos trivial si desea evitar la recursividad (puede ser una carga con estructuras grandes).
Siempre quise resolver el "dilema" de UL / LI para generar una matriz. El dilema es que cada elemento no sabe si los niños seguirán o no o cuántos elementos precedentes deben cerrarse. En otra respuesta, ya resolví eso usando un
RecursiveIteratorIteratory buscandogetDepth()y otra metainformación queIteratorproporcionó mi propio escrito : Obtener un modelo de conjunto anidado en un<ul>subárbol "cerrado" pero oculto . Esa respuesta también muestra que con los iteradores eres bastante flexible.Sin embargo, esa era una lista ordenada previamente, por lo que no sería adecuada para su ejemplo. Además, siempre quise resolver esto para una especie de estructura de árbol estándar y HTML
<ul>y<li>elementos.El concepto básico que se me ocurrió es el siguiente:
TreeNode- Resumen cada elemento en unTreeNodetipo simple que puede proporcionar su valor (por ejemploName) y si tiene hijos o no.TreeNodesIterator- ARecursiveIteratorque puede iterar sobre un conjunto (matriz) de estosTreeNodes. Eso es bastante simple porque elTreeNodetipo ya sabe si tiene hijos y cuáles.RecursiveListIterator- ARecursiveIteratorIteratorque tiene todos los eventos necesarios cuando itera de forma recursiva sobre cualquier tipo deRecursiveIterator:beginIteration/endIteration- Comienzo y final de la lista principal.beginElement/endElement- Comienzo y final de cada elemento.beginChildren/endChildren- Comienzo y final de cada lista de niños. EstoRecursiveListIteratorsolo proporciona estos eventos en forma de llamadas a funciones. las listas secundarias, como es típico en las<ul><li>listas, se abren y cierran dentro de su<li>elemento padre . Por lo tanto, elendElementevento se dispara después delendChildrenevento correspondiente. Esto podría cambiarse o configurarse para ampliar el uso de esta clase. Los eventos se distribuyen como llamadas de función a un objeto decorador para mantener las cosas separadas.ListDecorator- Una clase "decoradora" que es solo un receptor de los eventos deRecursiveListIterator.Empiezo con la lógica de salida principal. Tomada la
$treematriz ahora jerárquica , el código final se parece a lo siguiente:En primer lugar mirada nos dejó en el
ListDecoratorque simplemente se envuelve las<ul>y los<li>elementos y está decidiendo sobre cómo la estructura de la lista de salida es:El constructor toma el iterador de lista en el que está trabajando.
insetes solo una función auxiliar para una buena sangría de la salida. El resto son solo las funciones de salida para cada evento:Con estas funciones de salida en mente, este es el ciclo / resumen de salida principal nuevamente, lo reviso paso a paso:
Cree la raíz
TreeNodeque se utilizará para iniciar la iteración en:Esta
TreeNodesIteratores unaRecursiveIteratorque permite la iteración recursiva sobre un solo$rootnodo. Se pasa como una matriz porque esa clase necesita algo sobre lo que iterar y permite la reutilización con un conjunto de elementos secundarios que también es una matriz deTreeNodeelementos.Este
RecursiveListIteratores unRecursiveIteratorIteratorque proporciona dichos eventos. Para hacer uso de él, solo esListDecoratornecesario proporcionar un (la clase anterior) y asignarleaddDecorator:Luego, todo está configurado para pasarlo
foreachy generar cada nodo:Como muestra este ejemplo, toda la lógica de salida está encapsulada en la
ListDecoratorclase y este singleforeach. Todo el recorrido recursivo se ha encapsulado completamente en iteradores recursivos SPL que proporcionaron un procedimiento apilado, lo que significa que internamente no se realizan llamadas a funciones de recursividad.El basado en eventos le
ListDecoratorpermite modificar la salida específicamente y proporcionar múltiples tipos de listas para la misma estructura de datos. Incluso es posible cambiar la entrada ya que se han encapsulado los datos de la matrizTreeNode.El ejemplo de código completo:
Outpupt:
Demostración (variante PHP 5.2)
Una posible variante sería un iterador que itera sobre cualquiera
RecursiveIteratory proporciona una iteración sobre todos los eventos que pueden ocurrir. Un interruptor / caso dentro del bucle foreach podría lidiar con los eventos.Relacionado:
fuente
Bueno, primero convertiría la matriz directa de pares clave-valor en una matriz jerárquica
Eso puede convertir una matriz plana con parent_id e id en una jerárquica:
Luego, simplemente cree una función de renderizado:
fuente
Si bien la solución de Alexander-Konstantinov puede no parecer tan fácil de leer al principio, es genial y exponencialmente mejor en términos de rendimiento, esta debería haber sido votada como la mejor respuesta.
Gracias amigo, hice un benchmark en tu honor para comparar las 2 soluciones presentadas en este post.
Tenía un árbol plano @ 250k con 6 niveles que tenía que convertir y estaba buscando una mejor manera de hacerlo y evitar iteraciones recursivas.
Recurrencia vs referencia:
La salida habla por sí sola:
fuente
Bueno, para analizar UL y LI, sería algo como:
Pero me encantaría ver una solución que no requiera que recorra la matriz con tanta frecuencia ...
fuente
Esto es lo que se me ocurrió:
salidas:
fuente
Relación padre-hijo Matriz anidada
Obtiene todo el registro de la base de datos y crea una matriz anidada.
Imprimir datos de categorías y subcategorías en formato json
fuente
$ aa = $ this-> parseTree ($ árbol);
fuente
Pregunta vieja, pero yo también tuve que hacer esto y los ejemplos con recursividad me dieron dolor de cabeza. En mi base de datos tenemos una
locationstabla, que era unloca_idPK (Child) y una autorreferencialoca_parent_id(Parent).El objetivo es representar esta estructura en HTML. Por supuesto, la consulta simple puede devolver los datos en un orden fijo, pero no encontré lo suficientemente bien como para mostrar dichos datos de una manera natural. Lo que realmente quería era el manejo del recorrido del árbol de Oracle
LEVELpara ayudar con la visualización.Decidí utilizar la idea de una "ruta" para identificar de forma única cada entrada. Por ejemplo:
Ordenar la matriz por la ruta debería facilitar el proceso para una visualización significativa.
Me doy cuenta de que el uso de matrices y clases asociativas es una trampa, ya que oculta la complejidad recursiva de las operaciones, pero para mí esto parece más simple:
fuente
Cómo crear un menú y una vista de árbol dinámicos
Paso 1: Primero crearemos una tabla de vista de árbol en la base de datos mysql. esta tabla contiene cuatro columnas. id es el id de la tarea y name es el nombre de la tarea.
Paso 2: Método recursivo de vista de árbol que he creado debajo del método createTreeView () del árbol que llama recursivo si la identificación de la tarea actual es mayor que la identificación de la tarea anterior.
Paso 3: Cree un archivo de índice para mostrar la vista de árbol. Este es el archivo principal del ejemplo de vista de árbol. Aquí llamaremos al método createTreeView () con los parámetros requeridos.
Paso 4: Cree el archivo CSS style.css Aquí escribiremos todas las clases relacionadas con CSS, actualmente estoy usando la lista de pedidos para crear una vista de árbol. también puede cambiar la ruta de la imagen aquí.
Más detalles
fuente