Newsgroup: it.comp.www.php
Titolo: Generazione albero di menu

Ho un array (a dire il vero ï¿œ un database)
con un elenco di caterogorie, le quali hanno
tutte un id "parentid".
Se il parentid non ï¿œ presente oppure ï¿œ 0, allora
ï¿œ una categoria principale. Se invece ï¿œ presente,
il parentid corrisponde all'id della categoria della
quale il nodo attuale ï¿œ il figlio.
Semplifichiamo cosï¿œ:
$arr[] = array('id'=>1, 'parentid'=>'', 'nome'=>'PARENT');
$arr[] = array('id'=>2, 'parentid'=>1,  'nome'=>'FIGLIO');
$arr[] = array('id'=>3, 'parentid'=>1,  'nome'=>'FIGLIO2');
$arr[] = array('id'=>4, 'parentid'=>'', 'nome'=>'PARENT2');
$arr[] = array('id'=>5, 'parentid'=>'4', 'nome'=>'FIGLIO3');
Devo realizzare una funzione ricorsiva, che parta da
un nodo (di default 0, ovvero genera tutto l'albero) e che
mi restituisca un array giï¿œ ordinato con tutti i record al
suo interno.
Ad esempio:
$albero = genera_albero($arr, 0); // Parto dal nodo 0
PARENT
   +------ FIGLIO
   +------ FIGLIO2
PARENT2
   +------ FIGLIO3
Se invece richiamassi la funzione cosï¿œ:
$albero = genera_albero($arr, 4); // Parto dal nodo 4
dovrei ottenere solo:
PARENT2
   +------ FIGLIO3
Mi sapete aiutare?
-- 
Non tocca a noi dominare tutte le maree del mondo,
il nostro compito ï¿œ di fare il possibile per la
salvezza degli anni nei quali viviamo,
sradicando il male dai campi che conosciamo.

 
cercaFigli(inizio){
	select figli where padre = inizio
	while riga
		fai cose ...
		cercaFigli(riga['id']);
}
Il concetto è questo, ovviamente la sintassi no
Ciao

 Il concetto è questo, ovviamente la sintassi no
Ho dimenticato di dire che non voglio eseguire
4 milioni di query in una funzione ricorsiva.
E' un insulto alle prestazioni, ho risolto così:
<?
$array[] = array('id'=>1, 'parentid'=>'1', 'nome'=>'PARENT');
$array[] = array('id'=>2, 'parentid'=>'1', 'nome'=>'FIGLIO');
$array[] = array('id'=>3, 'parentid'=>'1', 'nome'=>'FIGLIO2');
$array[] = array('id'=>4, 'parentid'=>'4', 'nome'=>'PARENT2');
function generaAlbero($arr, $startid=0) {
    foreach ( $arr as $nodo ) {
       if ( $nodo['parentid'] == 0 ||
            $nodo['parentid'] == "" ||
            $nodo['id'] == $nodo['parentid'] ) {
	 // Nodo parent
          $nodi[$nodo['parentid']] = $nodo;
       } else {
	 // Nodo figlio
          $nodi[$nodo['parentid']]['children'][$nodo['id']] = $nodo;
       }
    }
    if ( $startid > 0 ) {
       // Mostro solo un nodo
       return $nodi[$startid];
    } else {
       // Mostro albero per intero
       return $nodi;
    }
}
$albero = generaAlbero($array);
print_r($albero);
echo "\n\n=====================================\n\n";
$albero = generaAlbero($array, 4);
print_r($albero);
?>
In questo modo faccio una sola query per prendere tutte
le categoria in una singola mandata.
Se anche fossero 2 milioni di record (pressochè impossibile)
ci metterebbe pochi millisecondi, se invece facessi la query
ricorsiva dentro la funzione, farebbe svariati milioni di
query, una per ogni record presente nel db, in modo da verificarne
la presenza di figli.
-- 
Non tocca a noi dominare tutte le maree del mondo,
il nostro compito è di fare il possibile per la


Gandalf Corvotempesta ha scritto:

Che ci metta meno php a scorrere un array piuttosto che un rdbms a
gestire una select non ne sarei proprio così certo, specialmente con
array di miolioni di righe (dal tuo esempio avevo capito che si parlasse
di dimensioni ben più piccole). Prova a fare dei test reali coi prepared
statement: praticamente azzeri l'overhead di interazione col db. Mi
interesserebbe molto sapere cosa sia più veloce e in che ordine di
grandezza.

 di dimensioni ben più piccole).
Il fatto è che se esegui 400 query, sovraccarichi due server o un
server + 2 processi (apache e mysql), se scorri solo un array
sovraccarichi solo il server web, che scala in maniera molto più
semplice rispetto ad un database.
Se butta male, a bilanciare dei server web ci metti relativamente
poco, a bilanciare dei server mysql è ben più problematico in
quanto devi tirare in ballo le repliche ed una infrastruttura
ad-hoc, più realizzare un software che bilanci le richieste su
più server o utilizzare un proxy.
Insomma, preferisco far collassare un server web che tenere
occupato un server mysql.