[php] threaded sorteren in een array

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • haling
  • Registratie: Mei 2003
  • Laatst online: 26-06 15:53
Heren, dames,

Ik ben een (simpel) threaded forumpje aan het schrijven en loop tegen het volgende aan:

Ik heb een procedure geschreven die uit een database de top-posts haalt en dan per post kijkt of er reacties op zijn en dan of daar weer reacties op zijn (etc). Als er geen reactie is, dan gaat hij weer 1 niveau hoger kijken en als daar niets meer te halen valt weer 1 hoger totdat we weer op top-niveau zijn. Daar opent hij de volgende top-post en herhaalt bovenstaand kunstje.

Dit werkt goed, maar... Er wordt per reply een query uitgevoerd, wat uiteindelijk performance gaat kosten.

Ik zat te denken om alle posts die in 1 thread staan in 1 array te gooien en dan intern in die array te gaan bepalen wat de volgorde en niveau van de post is. Dit wordt alleen iets te moeilijk voor dit amateurtje...

Op http://sait.nl/threaded.php kun je zien wat ik bedoel. Threads v1 is de werkende versie en v2 werkt niet (maar is al wel sneller!).

Ik heb dus deze array om te sorteren en 'levels' toe te voegen:
$array['threadnr']['id' en 'reply_op_id' en 'inhoud']

dus zoiets:

$array[1]: id=1 parent=0 (top post)
$array[1]: id=2 parent=1 (antwoord op id1)
$array[1]: id=3 parent=1 (weer een antwoord op id1)
$array[1]: id=4 parent=2 (antwoord op id2)

moet worden:

id1
|--id2
|--|--id4
|--id3

pfff... ik ben benieuwd of hier iemand pindakaas van kan maken. 8)7

Cheers!

De 'oude' manier:
code:
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
$RESULT[0]=dbQuery("SELECT * FROM nested WHERE parent=0");
    while ($ARRAY[0]=mysql_fetch_array($RESULT[0])) { // zolang er top-posts zijn
        echo "Post id: ".$ARRAY[0]['id']." \"".$ARRAY[0]['text']."\"<br>"; // echo de top-post
        $LEVEL=1;
        while (1) {
            $RESULT[$LEVEL]=dbQuery("SELECT * FROM nested WHERE parent=".$ARRAY[$LEVEL-1]['id']); // selecteer alle leafs van de post
            while (1) { // zolang er items zijn in de huidige level
                $ARRAY[$LEVEL]=mysql_fetch_array($RESULT[$LEVEL]);
                $AANTAL[$LEVEL]=mysql_num_rows($RESULT[$LEVEL]);
                (!isset($TELLER[$LEVEL])) ? $TELLER[$LEVEL]=1 : $TELLER[$LEVEL]++;
                if ($TELLER[$LEVEL]<=$AANTAL[$LEVEL]) {
                    echo createPost($LEVEL,$ARRAY[$LEVEL]);
                    $RESULT[$LEVEL+1]=dbQuery("SELECT * FROM nested WHERE parent=".$ARRAY[$LEVEL]['id']); // controleer of de post een kind heeft
                    if (mysql_num_rows($RESULT[$LEVEL+1])>0) { //zijn er kinderen?
                        $LEVEL++; //ga er dan naar toe
                    }
                }
                else $LEVEL--;
                if ($LEVEL<1) break;
            }
            unset($TELLER);
            if ($LEVEL<1) break;
        }
        echo "<br>";
    }

[ Voor 46% gewijzigd door haling op 14-06-2006 15:01 . Reden: extra info ]


Acties:
  • 0 Henk 'm!

  • Gonadan
  • Registratie: Februari 2004
  • Nu online

Gonadan

Admin Beeld & Geluid, Harde Waren
Kan je daar niet sort of rsort voor gebruiken?
Dan moet je alleen de keys in het array misschien even op een andere volgorde zetten.
Hij sorteert namelijk eerst op de eerste, dan de 2e enz... :)

Look for the signal in your life, not the noise.

Canon R6 | 50 f/1.8 STM | 430EX II
Sigma 85 f/1.4 Art | 100-400 Contemporary
Zeiss Distagon 21 f/2.8


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Als eerste neem ik aan dat je per post een id en een parrent id hebt. Als ik vervolgens ook nog aan kan nemen dat de id van een post altijd hoger is dan zijn parrent id en dat de rootpost een een parrent id 0 of null heeft dan zou je het volgende kunnen doen:

Zorg er eerst voor dat je een leuke datastructuur hebt (liefst classes ipv array's. Array's zijn enorm onduidelijk)


Haal alle post van een thread uit de database en sorteer deze op parrent id.
Verwerk elke rij alsvolgt:
creeer een post object van die rij.
sla deze op in een map onder zijn id. (array's zijn in php als map te gebruiken)
zoek in die map de parrent op en voeg dit object als child toe.

Als je nu alles verwerkt hebt dan heb je een map met alle posts, maar elke post heeft iig een lijst met al zijn kinderen die vervolgens weer een lijst heeft van al zijn kinderen. Je hoeft nu uit de lijst alleen maar de rootpost te halen en deze tijdens het afdrukken op dezelfde manier te behandelen als je orginele code.

In principe zou je ook op id kunnen sorteren. Dan heb je ook de garantie dat tijdens de bewerking van post X zijn parrent al aangemaakt is. De reden dat ik op parentid laat sorteren is omdat je dan dezelfde garantie kunt geven, maar daarnaast ook een optimalisatie kunt doen omdat je alle kinderen van 1 post bij elkaar hebt staan en deze maar 1x in de map op zou hoeven te zoeken.

Zorg er wel voor dat je op 1 of andere manier kunt filteren welke post bij welke thread hoort. Dit kun je doen door overal ook een topic id oid mee te geven. DOe je dit niet dan ben je altijd een complete boom aan het opbouwen van je complete forum.

[ Voor 14% gewijzigd door Janoz op 14-06-2006 12:46 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • haling
  • Registratie: Mei 2003
  • Laatst online: 26-06 15:53
OK, klinkt logisch, maar jouw verhaal omzetten naar code gaat pittig worden...

Ik heb ook nog niet eerder met classes gewerkt (behalve dtemplate)

[ Voor 111% gewijzigd door haling op 14-06-2006 13:34 ]