Cela nécessite une fonction récursive très basique pour analyser les paires enfant / parent en une structure arborescente et une autre fonction récursive pour l'imprimer. Une seule fonction suffirait mais en voici deux pour plus de clarté (une fonction combinée peut être trouvée à la fin de cette réponse).
Initialisez d'abord le tableau de paires enfant / parent:
$tree = array(
'H' => 'G',
'F' => 'G',
'G' => 'D',
'E' => 'D',
'A' => 'E',
'B' => 'C',
'C' => 'E',
'D' => null
);
Ensuite, la fonction qui analyse ce tableau dans une structure arborescente hiérarchique:
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;
}
Et une fonction qui parcourt cet arbre pour imprimer une liste non ordonnée:
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>';
}
}
Et l'utilisation réelle:
$result = parseTree($tree);
printTree($result);
Voici le contenu 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 vous voulez un peu plus d'efficacité, vous pouvez combiner ces fonctions en une seule et réduire le nombre d'itérations effectuées:
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>';
}
}
Vous ne sauvegarderez que 8 itérations sur un ensemble de données aussi petit que celui-ci, mais sur des ensembles plus grands, cela pourrait faire une différence.
Encore une autre fonction pour créer un arbre (aucune récursivité impliquée, utilise des références à la place):
Renvoie un tableau hiérarchique comme celui-ci:
Qui peut facilement être imprimé sous forme de liste HTML en utilisant la fonction récursive.
la source
Une autre manière plus simplifiée de convertir la structure plate
$tree
dans une hiérarchie. Un seul tableau temporaire est nécessaire pour l'exposer:C'est tout pour obtenir la hiérarchie dans un tableau multidimensionnel:
La sortie est moins triviale si vous voulez éviter la récursivité (peut être un fardeau avec de grandes structures).
J'ai toujours voulu résoudre le «dilemme» UL / LI pour la sortie d'un tableau. Le dilemme est que chaque élément ne sait pas si les enfants suivront ou non ou combien d'éléments précédents doivent être fermés. Dans une autre réponse, j'ai déjà résolu cela en utilisant un
RecursiveIteratorIterator
et en recherchantgetDepth()
et d'autres méta-informations que ma propre écriture aIterator
fournies: Obtenir un modèle d'ensemble imbriqué dans un sous-<ul>
arbre «fermé» mais en le cachant . Cette réponse montre également qu'avec les itérateurs, vous êtes assez flexible.Cependant, c'était une liste pré-triée, donc ne conviendrait pas à votre exemple. De plus, j'ai toujours voulu résoudre ce problème pour une sorte d'arborescence standard, du HTML
<ul>
et des<li>
éléments.Le concept de base que j'ai proposé est le suivant:
TreeNode
- Abstractionne chaque élément dans unTreeNode
type simple qui peut fournir sa valeur (par exempleName
) et s'il a ou non des enfants.TreeNodesIterator
- UnRecursiveIterator
qui est capable d'itérer sur un ensemble (tableau) de ceux-ciTreeNodes
. C'est assez simple car leTreeNode
type sait déjà s'il a des enfants et lesquels.RecursiveListIterator
- UnRecursiveIteratorIterator
qui a tous les événements nécessaires lorsqu'il itère récursivement sur tout type deRecursiveIterator
:beginIteration
/endIteration
- Début et fin de la liste principale.beginElement
/endElement
- Début et fin de chaque élément.beginChildren
/endChildren
- Début et fin de chaque liste d'enfants. CelaRecursiveListIterator
ne fournit ces événements que sous forme d'appels de fonction. les listes d'enfants, comme c'est typique pour les<ul><li>
listes, sont ouvertes et fermées à l'intérieur de son<li>
élément parent . Par conséquent, l'endElement
événement est déclenché après l'endChildren
événement correspondant. Cela pourrait être modifié ou rendu configurable pour élargir l'utilisation de cette classe. Les événements sont ensuite distribués sous forme d'appels de fonction à un objet décorateur, pour séparer les choses.ListDecorator
- Une classe "décorateur" qui n'est qu'un récepteur des événements deRecursiveListIterator
.Je commence par la logique de sortie principale. Prenant le
$tree
tableau maintenant hiérarchique , le code final ressemble à ce qui suit:Tout d' abord le regard de let dans le
ListDecorator
que le simple enveloppe les<ul>
et<li>
éléments et décider de la façon dont la structure de la liste est sortie:Le constructeur prend l'itérateur de liste sur lequel il travaille.
inset
est juste une fonction d'aide pour une belle indentation de la sortie. Le reste n'est que les fonctions de sortie pour chaque événement:Avec ces fonctions de sortie à l'esprit, c'est à nouveau la boucle / boucle de sortie principale, je la parcoure pas à pas:
Créez la racine
TreeNode
qui sera utilisée pour démarrer l'itération sur:C'est
TreeNodesIterator
unRecursiveIterator
qui permet une itération récursive sur le$root
nœud unique . Il est passé sous forme de tableau car cette classe a besoin de quelque chose pour itérer et permet la réutilisation avec un ensemble d'enfants qui est également un tableau d'TreeNode
éléments.C'est
RecursiveListIterator
unRecursiveIteratorIterator
qui fournit lesdits événements. Pour l'utiliser, il suffitListDecorator
de fournir un (la classe ci-dessus) et de lui attribueraddDecorator
:Ensuite, tout est configuré pour juste au-
foreach
dessus et afficher chaque nœud:Comme le montre cet exemple, toute la logique de sortie est encapsulée dans la
ListDecorator
classe et ce singleforeach
. L'ensemble du parcours récursif a été entièrement encapsulé dans des itérateurs récursifs SPL qui ont fourni une procédure empilée, ce qui signifie qu'en interne aucun appel de fonction de récursivité n'est effectué.L'événement basé
ListDecorator
vous permet de modifier spécifiquement la sortie et de fournir plusieurs types de listes pour la même structure de données. Il est même possible de modifier l'entrée car les données du tableau ont été encapsulées dansTreeNode
.L'exemple de code complet:
Outpupt:
Démo (variante PHP 5.2)
Une variante possible serait un itérateur qui itère sur tout
RecursiveIterator
et fournit une itération sur tous les événements qui peuvent se produire. Un commutateur / boîtier à l'intérieur de la boucle foreach pourrait alors gérer les événements.En relation:
la source
Eh bien, d'abord, je transformerais le tableau simple de paires clé-valeur en un tableau hiérarchique
Cela peut convertir un tableau plat avec parent_id et id en un tableau hiérarchique:
Ensuite, créez simplement une fonction de rendu:
la source
Bien que la solution d' Alexander-Konstantinov puisse ne pas sembler aussi facile à lire au début, elle est à la fois géniale et exponentiellement meilleure en termes de performances, cela aurait dû être élue comme la meilleure réponse.
Merci mon pote, j'ai fait un benchmark en votre honneur pour comparer les 2 solutions présentées dans ce post.
J'avais un arbre plat @ 250k avec 6 niveaux que je devais convertir et je cherchais un meilleur moyen de le faire et d'éviter les itérations récursives.
Récursivité vs référence:
La sortie parle d'elle-même:
la source
Eh bien, pour analyser les UL et les LI, ce serait quelque chose comme:
Mais j'aimerais voir une solution qui ne vous oblige pas à parcourir le tableau si souvent ...
la source
Voici ce que j'ai trouvé:
les sorties:
la source
Relation parent-enfant nested Array
Récupère tous les enregistrements de la base de données et crée un tableau imbriqué.
Imprimer les données des catégories et sous-catégories au format json
la source
$ aa = $ this-> parseTree ($ tree);
la source
Ancienne question, mais moi aussi j'ai dû le faire et les exemples avec récursivité m'ont donné mal à la tête. Dans ma base de données, nous avons une
locations
table, qui était unloca_id
PK (enfant) et un auto-référencementloca_parent_id
(parent).Le but est de représenter cette structure en HTML. La simple requête peut de couyrse renvoyer les données dans un ordre fixe mais je n'ai pas trouvé assez bien pour afficher ces données de manière naturelle. Ce que je voulais vraiment, c'était la gestion de l'arborescence Oracle avec
LEVEL
pour aider à l'affichage.J'ai décidé d'utiliser l'idée d'un «chemin» pour identifier de manière unique chaque entrée. Par exemple:
Le tri du tableau par chemin devrait faciliter le traitement pour un affichage significatif.
Je me rends compte que l'utilisation de tableaux et de tris associatifs est une triche car elle cache la complexité récursive des opérations, mais pour moi, cela semble plus simple:
la source
Comment créer une arborescence et un menu dynamiques
Étape 1: Nous allons d'abord créer une table d'arborescence dans la base de données mysql. ce tableau contient quatre colonnes. id est l'id de la tâche et nom est le nom de la tâche.
Étape 2: Méthode récursive de l'arborescence J'ai créé ci-dessous la méthode createTreeView () de l'arborescence qui appelle récursive si l'ID de la tâche actuelle est supérieur à l'ID de la tâche précédente.
Étape 3: Créez un fichier d'index pour afficher l'arborescence. Ceci est le fichier principal de l'exemple de treeview ici, nous allons appeler la méthode createTreeView () avec les paramètres requis.
Étape 4: Créer un fichier CSS style.css Ici, nous allons écrire toutes les classes liées au CSS, actuellement j'utilise la liste de commande pour créer une arborescence. vous pouvez également modifier le chemin de l'image ici.
Plus de détails
la source