Trier une array - arbre

Trier une array - arbre - PHP - Programmation

Marsh Posté le 21-02-2008 à 17:47:12    

Bonjour tous,  
 
Avec une requête SQL j'obtiens une array de ce type :  

Code :
  1. $myarray[0]["id"]=1;
  2. $myarray[0]["parent"]=0;
  3. $myarray[1]["id"]=2;
  4. $myarray[1]["parent"]=0;
  5. $myarray[2]["id"]=3;
  6. $myarray[2]["parent"]=1;
  7. $myarray[3]["id"]=4;
  8. $myarray[3]["parent"]=1;
  9. $myarray[4]["id"]=5;
  10. $myarray[4]["parent"]=2;
  11. $myarray[5]["id"]=6;
  12. $myarray[5]["parent"]=1;
  13. $myarray[6]["id"]=7;
  14. $myarray[6]["parent"]=3;


 
Je voudrais trier cette array par ID, chacun suivi immédiatement de ses enfants et cela de manière récursive.
 
Dans l'exemple ci-dessus, l'array nouvellement triée que je voudrais obtenir aurait donc les valeurs de $myarray dans cette ordre :  
0 - 2 - 6 - 3 - 5 - 1 - 4  
c'est-à-dire l'arbre d'IDs représenté dans l'array  :

IDs :  
+ 1
| + 3
| | + 7
| +  4
| +  6
+ 2
| + 5

A noter que 3, 4 et 6 peuvent être dans n'importe quel ordre puisque tous enfants de 1.
 
 
Tout d'abord j'ai essayé de trier ma requête SQL, pour éviter de devoir jouer avec des array ...  mais ça semble impossible en une seule requête, même avec des requêtes imbriquées (puisque chaque ligne exige de voir si son parent a déjà été sélectionné, ou pire, son parent peut très bien se trouver "après" dans la table)... Je peux évidemment faire des requêtes récursives via scripts PHP, genre je prends tous les ID dont le parent est 0, puis un par un je sélectionne ses enfants, etc. etc. mais ça va me faire trop de requêtes, j'en voudrais une seule (rien que dans l'exemple ultra simplifié ci-dessus j'aurais 8 requêtes si je compte bien)
 
J'ai essayé d'explorer la voie avec multisort() mais je ne vois vraiment pas quoi faire, je suis un peu bloqué ..
 
Ce que je veux faire ne me semble pas si difficile, pourtant je ne trouve rien de véritablement probant dans les miyyons d'articles sur le PHP array sorting sur le web ...  
 
quelqu'un aurait-il une piste ?  
 
En vous r'merciant  :hello:  
 

Reply

Marsh Posté le 21-02-2008 à 17:47:12   

Reply

Marsh Posté le 22-02-2008 à 01:15:22    

Erf :D

 

Moi, là comme ça, je ferais ça par insertions :
- tu insères d'abord les éléments dont le parent est 0
- ensuite pour chacun tu cherches s'il a des enfants, si oui tu les insère juste apres leur parent
- c'est reparti pour un tour etc

 

Tout ça avec un tableau de départ et un tableau d'arrivée, et tu "déplace" les éléments. Le truc est fini quand le tableau de départ est vide...

 

Et pour te faciliter la tache, tu fais à la base un tableau de la forme
"id" => "parent" et pas "indexquisertarien" => ["id", "parent"]

 

Pour ce dernier point, je pense que ça peut bien t'aider, pour le premier (la méthode de tri), je sais pas si c'est le mieux optimisé...


Message édité par theredled le 22-02-2008 à 01:16:13

---------------
Contes de fées en yaourt --- --- zed, souviens-toi de ma dernière lettre. --- Rate ta musique
Reply

Marsh Posté le 22-02-2008 à 10:21:20    

Merci pour ta réponse,

 
Citation :

Moi, là comme ça, je ferais ça par insertions :
- tu insères d'abord les éléments dont le parent est 0
- ensuite pour chacun tu cherches s'il a des enfants, si oui tu les insère juste apres leur parent
- c'est reparti pour un tour etc

 

La manière dont fonctionne un "fetch" dans un result set SQL me fait dire que cette solution n'est pas possible ... elle demanderait que PHP ait des pointeurs qui me permettent de me ballader dans le result set et ça, malheureusement, ça n'existe pas :(

 
Citation :

Et pour te faciliter la tache, tu fais à la base un tableau de la forme
"id" => "parent" et pas "indexquisertarien" => ["id", "parent"]

 

ça en revanche me paraît un excellent commencement, vrai que l' "indexquisertàrien", que j'obtenais tout simplement parce que je faisais un array_push() pour peupler $myarray, est totalement inutile et ne va pas faciliter la chose ...

 

j'aurais donc un truc du genre :

Code :
  1. $myarray[1]=0;
  2. $myarray[2]=0;
  3. $myarray[3]=1;
  4. $myarray[4]=1;
  5. $myarray[5]=2;
  6. $myarray[6]=1;
  7. $myarray[7]=3;
 

et je voudrais toujours obtenir, donc, l'ordre  1 - 3  - 7 - 4  - 6 -  2 - 5

Message cité 1 fois
Message édité par ZeBix le 22-02-2008 à 10:21:38
Reply

Marsh Posté le 22-02-2008 à 11:48:42    

ZeBix a écrit :

La manière dont fonctionne un "fetch" dans un result set SQL me fait dire que cette solution n'est pas possible ... elle demanderait que PHP ait des pointeurs qui me permettent de me ballader dans le result set et ça, malheureusement, ça n'existe pas :(


Ben tu mets ton result set dans un tableau classique avant et voilou :??: j'avais cru comprendre que tu le faisais déja...

 

De toute façon tu es obligé si tu veux le réindexer.


Message édité par theredled le 22-02-2008 à 11:50:05

---------------
Contes de fées en yaourt --- --- zed, souviens-toi de ma dernière lettre. --- Rate ta musique
Reply

Marsh Posté le 22-02-2008 à 13:51:14    

Heu oui en fait , je n'avais pas bien compris ta réponse, c'est clair maintenant :)
 
Merci pour le tuyau je pense que ça fera l'affaire ! Pas évident parce qu'il faut bien tricoter (merci pour l'idée des index qui sont les ID, ça accélère le bidule) mais le principal c'est que j'ai mon résultat...  
 
Si quelqu'un a une idée plus optimisée, je suis également preneur :jap:

Reply

Marsh Posté le 22-02-2008 à 14:17:06    

http://dev.mysql.com/tech-resource [...] -data.html


---------------
Software and cathedrals are much the same - first we build them, then we pray.
Reply

Marsh Posté le 22-02-2008 à 14:29:54    

Voila l'homme qu'il nous fallait [:kbchris]


Message édité par theredled le 22-02-2008 à 14:30:15

---------------
Contes de fées en yaourt --- --- zed, souviens-toi de ma dernière lettre. --- Rate ta musique
Reply

Marsh Posté le 22-02-2008 à 15:16:46    

Merci pour le link, anapajari, mais je vois deux solutions proposées sur cette page :

 

- Une qui requiert de connaître quelle est la profondeur maximale de l'arbre (puisqu'il faut un self join pour chaque niveau), et dans ma structure de données cette profondeur est totalement dynamique.
- Une qui requiert de changer complètement l'organisation des données et l'insertion de celles-ci, pour utiliser les "nodes" left et right. Le modèle est du reste très intéressant mais malheureusement comme beaucoup de concepteurs de scripts, je n'ai pas la mainmise sur tous les aspects de mon S.I., et ne peux donc pas procéder à de tels changements ...
 

Message cité 2 fois
Message édité par ZeBix le 22-02-2008 à 15:17:20
Reply

Marsh Posté le 22-02-2008 à 15:43:18    

ZeBix a écrit :


- Une qui requiert de connaître quelle est la profondeur maximale de l'arbre (puisqu'il faut un self join pour chaque niveau), et dans ma structure de données cette profondeur est totalement dynamique.


Ne peux-tu pas trouver un moyen de calculer cette profondeur ?

 

edit: en faisant SELECT count( DISTINCT id_parent) tu obtiens le nb de niveau hiérarchique...

 

Message cité 2 fois
Message édité par babasss le 22-02-2008 à 15:49:53

---------------
Feedback : http://forum.hardware.fr/hfr/Achat [...] 2666_1.htm
Reply

Marsh Posté le 22-02-2008 à 15:59:06    

ZeBix a écrit :

Merci pour le link, anapajari, mais je vois deux solutions proposées sur cette page :  
 
- Une qui requiert de connaître quelle est la profondeur maximale de l'arbre (puisqu'il faut un self join pour chaque niveau), et dans ma structure de données cette profondeur est totalement dynamique.
- Une qui requiert de changer complètement l'organisation des données et l'insertion de celles-ci, pour utiliser les "nodes" left et right. Le modèle est du reste très intéressant mais malheureusement comme beaucoup de concepteurs de scripts, je n'ai pas la mainmise sur tous les aspects de mon S.I., et ne peux donc pas procéder à de tels changements ...  


Non y'a pas 2 solutions, y'a une problématique "les données hierarchisées" en sql.
 
Ensuite une présentation des listes adjacentes (la solution que tu utilises comme beaucoup de gens) qui insiste sur les défauts de celle-ci. Defauts que tu as toi même constaté puisque tu es bloqué sur le problème de profondeur.
 
Enfin la solution des "nested set" qui réponds parfaitement à ton besoin et présente de nombreux avantages (surtout en terme de rapidité).  
C'est, ama, LA solution a utilisé dans ce genre de situation.
Quand tu dis "je n'ai pas la main sur le SI" ça veut dire que tu n'as pas le droit de modifier la structure d'une table :??:
 
Et si tu peux vraiment pas, alors la "tripatouillage" via un truc récursif en php reste certainement la meilleure solution.


---------------
Software and cathedrals are much the same - first we build them, then we pray.
Reply

Marsh Posté le 22-02-2008 à 15:59:06   

Reply

Marsh Posté le 22-02-2008 à 15:59:11    

babasss a écrit :

edit: en faisant SELECT count( DISTINCT id_parent) tu obtiens le nb de niveau hiérarchique...

 

Gné  :heink:

 

ID : 1 - ID_parent : 0
ID : 2 - ID_parent : 0
ID : 3 - ID_parent : 0
ID : 4 - ID_parent : 1
ID : 5 - ID_parent : 2
ID : 6 - ID_parent : 3

 

Select count (distinct ID_parent) --> 4
Prodondeur de niveau : 2

 


anapajari a écrit :


Enfin la solution des "nested set" qui réponds parfaitement à ton besoin et présente de nombreux avantages (surtout en terme de rapidité).
C'est, ama, LA solution a utilisé dans ce genre de situation.
Quand tu dis "je n'ai pas la main sur le SI" ça veut dire que tu n'as pas le droit de modifier la structure d'une table :??:

 

Et si tu peux vraiment pas, alors la "tripatouillage" via un truc récursif en php reste certainement la meilleure solution.

 

La structure de la table je pense pouvoir la modifier, mais la manière dont les informations sont entrées dedans non. Donc si la solution des nested sets demande des informations complémentaires, je peux probablement changer celles qui existent déjà via des scripts, mais il va falloir changer tout le processus d'encodage (la structure hiérarchisée sur laquelle je travaille étant en évolution) et ça c'est une autre paire de manches ... :/

 

Enfin quoi qu'il en soit pour toute structure ultérieure j'analyserai ce modèle avec attention car ça semble être le top indeed ...

 

Message cité 1 fois
Message édité par ZeBix le 22-02-2008 à 16:06:52
Reply

Marsh Posté le 22-02-2008 à 16:00:03    

babasss a écrit :


Ne peux-tu pas trouver un moyen de calculer cette profondeur ?

 

edit: en faisant SELECT count( DISTINCT id_parent) tu obtiens le nb de niveau hiérarchique...

 



Nop, si tu as 1400 parents de niveau 1 sans enfants, ça te retournera 1400, par ex :o

 

[:grilled]


Message édité par theredled le 22-02-2008 à 16:00:33

---------------
Contes de fées en yaourt --- --- zed, souviens-toi de ma dernière lettre. --- Rate ta musique
Reply

Marsh Posté le 22-02-2008 à 16:13:00    

ZeBix a écrit :


Gné  :heink:  
 
ID : 1 - ID_parent : 0
ID : 2 - ID_parent : 0
ID : 3 - ID_parent : 0
ID : 4 - ID_parent : 1
ID : 5 - ID_parent : 2
ID : 6 - ID_parent : 3
 
Select count (distinct ID_parent) --> 4
Prodondeur de niveau : 2


Sauf que dans ce cas, la profondeur est de 3 (car il faut compter 0 qui est un niveau malgré lui). De toutes facons, ca ne change rien => je m'ai trompé  [:sisicaivrai]


Message édité par babasss le 22-02-2008 à 16:13:22

---------------
Feedback : http://forum.hardware.fr/hfr/Achat [...] 2666_1.htm
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed