[PHP] Array sorteren op bepaalde kolom

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
In mijn CMS'je gebruik ik twee recursieve functies om de volgende tabel in een net menuutje te zetten:

Afbeeldingslocatie: http://www.danandan.luna.nl/tbl_nodes.gif

In dit voorbeeld heb ik "Overzicht" (nid=97) aangeklikt. Wat gebeurt er? De eerste functie bepaalt het pad van nid=97 naar de top (dus: 97 - 95 - 1 - 0) en de tweede loopt terug langs alle menu items om de boom te tekenen:

Afbeeldingslocatie: http://www.danandan.luna.nl/moet.gif

Dit alles kost mij in dit geval 7 queries. Omdat ik mijn systeem zo efficient mogelijk wil hebben, probeer ik nu een stukje code te schrijven dat alle menu items in 1 query selecteert en in een array stopt, waarna ik op de server middels een recursieve functie de boom teken:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
$result = db_query("SELECT * FROM nodes");

for ($i = 0; $i < db_num_rows($result); $i++)
{
  $node = db_fetch_array($result);
  $navitems[$node['nid']] = Array('pid'=>$node['pid'], 
                                  'title'=>$node['title'],
                                  'alias'=>$node['alias'],
                                  'weight'=>$node['weight']);
}


function buildMenu($menuItems, $activeItem, $curItem=0, $depth = 0) 
{ 
  $unfoldItems = array($activeItem); 
  while ($unfoldItems[count($unfoldItems)-1] != 0) 
    $unfoldItems[] = $menuItems[$unfoldItems[count($unfoldItems)-1]]['pid'];

  $first = true; 
  foreach ($menuItems as $itemKey=>$item) 
  { 
    if ($item['pid'] == $curItem) 
    { 
      if ($first) 
      {     
        if ($depth > 0) echo '<tr><td>&nbsp;</td><td>'; 
        echo '<table border="1">';
        $first = false; 
      } 
      
      echo '<tr><td>&gt;</td>';
            
      if ($activeItem == $itemKey) 
        echo '<td>'.$item['title'].'</td></tr>';
      else 
        echo '<td><a href="'.$item['alias'].'">'.$item['title'].'</a></td></tr>';

      if (in_array($itemKey, $unfoldItems)) 
        buildMenu($menuItems, $activeItem, $itemKey, $depth + 1 ); 
      } 
    } 
     
    if (!$first) 
    { 
      echo '</table>'; 
      if ($depth > 0)
        echo '</td></tr>'; 
    } 
} 

buildMenu($navitems, 97);

De output van al dit moois is bijna goed, op 1 puntje na: de nodes zijn niet gesorteerd op "weight" en ik weet ook niet hoe ik dat moet doen:

Afbeeldingslocatie: http://www.danandan.luna.nl/nu.gif

Ik heb gezocht op php.net, maar de functie asort laat de gebruiker geen property definieren waarop je kunt sorteren. Bovendien, waar moet ik deze dan in mijn functie aanroepen? Genoeg vragen dus. Ik hoop dat jullie mij op weg kunnen helpen. Voor de duidelijkheid: het menuutje moet er dus uitzien zoals in het eerste plaatje :)

Als de functie uiteindelijk werkt ga ik kijken wat sneller is, en wat de winst is. De boom zal redelijkerwijs nooit meer dan 1000 nodes bevatten. Vraag me af of MySQL snel 1000 nodes geselecteerd krijgt...ook graag hierover jullie ervaringen...

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Gebruik usort(), daarmee kun je een eigen sorteerfunctie maken, die dus sorteert op lengte van de string. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

Verwijderd

"ORDER BY pid, weight ASC" bij de query plakken? :)

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Hahahaha! Wat ontzettend simpel zeg...dat ik daar nou niet op gekomen ben?! Ik zat idd ook al te denken over usort en eigen functies, maar makkelijker (en sneller!) dan dit kan niet :) Blijft mijn tweede vraag nog staan - wat zijn jullie ervaringen met recursieve menu-bomen? Vuren jullie ook een losse query per keer af of selecteer je alles in 1 keer en doe je het op een soortgelijke manier?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Reveller schreef op 02 november 2004 @ 19:42:
Hahahaha! Wat ontzettend simpel zeg...dat ik daar nou niet op gekomen ben?! Ik zat idd ook al te denken over usort en eigen functies, maar makkelijker (en sneller!) dan dit kan niet :) Blijft mijn tweede vraag nog staan - wat zijn jullie ervaringen met recursieve menu-bomen? Vuren jullie ook een losse query per keer af of selecteer je alles in 1 keer en doe je het op een soortgelijke manier?
Ik geloof dat over het algemeen een array eenmalig ingelezen wordt, en deze een voor een afgewerkt wordt tot die leeg is. Is minder belastend dan een query per rij. :P

Overigens, ik had niet gezien dat je een kolom weight had, dacht dat je met weight te lengte van de string bedoelde. :+

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • ripexx
  • Registratie: Juli 2002
  • Laatst online: 17:49

ripexx

bibs

Reveller schreef op 02 november 2004 @ 19:42:
Hahahaha! Wat ontzettend simpel zeg...dat ik daar nou niet op gekomen ben?! Ik zat idd ook al te denken over usort en eigen functies, maar makkelijker (en sneller!) dan dit kan niet :) Blijft mijn tweede vraag nog staan - wat zijn jullie ervaringen met recursieve menu-bomen? Vuren jullie ook een losse query per keer af of selecteer je alles in 1 keer en doe je het op een soortgelijke manier?
Ik haal op dit moment de gehele tree op uit de DB. Dan loop ik met PHP met een recusieve functie door de array op zoek naar de children. Maar het is niet snel en als de tree nog verder groeit wordt het bijna ondoenlijk. Ik genereer dan ook een statisch menu aan de hand van de output. Nu is de reden om te optimaliseren ook niet meer nodig :P

PHP en recursie staan bijna altijd garant voor traag. Laatst nog zo'n discussie over geweest. Ook zijn er slimmere methoden om trees in een relationeel model op te slaan. Dan kost het inserten relatief meer reken werk en updates maar is het selecteren van subtrees stukken sneller.

buit is binnen sukkel


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
ripexx schreef op 02 november 2004 @ 19:54:
[...]
PHP en recursie staan bijna altijd garant voor traag. Laatst nog zo'n discussie over geweest. Ook zijn er slimmere methoden om trees in een relationeel model op te slaan. Dan kost het inserten relatief meer reken werk en updates maar is het selecteren van subtrees stukken sneller.
Weet ik, zoals het sitepoint artikel dat vaak wordt aangehaald indeze. Feit is dat ik dit model zo goed als geheel uitgewerkt heb liggen, maar het heeft in mijn ogen een groot nadeel: het is niet geschikt als "uitklapbaar" navigatie menu. Het is ontzettend snel als je de hele boom uitgeklapt wil laten zien, maar je hebt nog steeds recursie nodig als je bepaalde delen ingeklapt wil laten...volgens mij zit je bij navigatie menu's ofwel aan de server ofwel aan de client kant aan recursie vast...de vraag is dan wat het meest efficient is: alles ineens ophalen en PHP laten werken of een query voor elke laag afvuren...

[ Voor 5% gewijzigd door Reveller op 02-11-2004 20:46 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • MisterData
  • Registratie: September 2001
  • Laatst online: 29-08 20:29
Google/Got Search eens op het Celko Tree Model, dan vindt je een hoop informatie over hoe je een dergelijke tree een stuk handiger (iig snellere snelheid bij bekijken tree, inserten is inderdaad trager) kunt opslaan :) Ik gebruik het zelf in een soort 'hybride'-systeem: zowel het systeem met parent-id als het Celko-model :)
Pagina: 1