PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Ein altes Navigationsmenu sortieren

with 12 comments

Ich habe eine kleine Programmieraufgabe für euch.

Ich habe ein altes Projekt, in dem ich folgende Navigationsstruktur in der Datenbank habe:

menuidparentidtitlelevelsortid
13Wurm 1.1210
26Vogel 2.1230
30Tiger 1110
46Hund 2.2240
53Katze 1.2211
60Pferd 2120
71Baer 1.1.130
83Schwein 1.3212
94Esel 2.2.130

Nun möchte ich diese Menüpunkte sortiert ausgeben, und zwar in der folgenden Reihenfolge:

Tiger 1
  Wurm 1.1
    Baer 1.1.1
  Katze 1.2
  Schwein 1.3
Pferd 2
  Vogel 2.1
  Hund 2.2
    Esel 2.2.1

Die Sortierreihenfolge muss anhand der menuid, parentid, level und sortid berechnet werden. Eine parentid verweist auf den Elternknoten, sprich er ist darunter einzusortieren. Zwei Einträge mit der selben parentid sind nach der Spalte sortid zu sortieren.

Der Wurm ist ein Kindknoten vom Tiger, der Bär ist ein Kindknoten vom Wurm. Die Katze ist auch ein Kindknoten vom Tiger, hat aber die höhere sortid, muss also nach dem Wurm einsortiert werden.

Es ist ein altes Projekt mit dieser Struktur, und die Frage ist wie man das am einfachsten und schnellsten sortiert?

Geht das ganze mit einem SQL-Query? Das wäre natürlich die beste Lösung, aber mir ist kein solcher Query eingefallen der das Problem lösen könnte.

Also muss es in PHP sortiert werden. Ich habe das ganze in ein PHP-Array gepackt und hier für euch zum Spielen bereitgestellt:

http://3v4l.org/PTuRc

Dort könnt ihr an dem Algorithmus arbeiten, sodass aus dem Ursprungs-Array das Ziel-Array wird. Nachdem ihr „eval()“ gedrückt habt könnt ihr einfach die URL hier in die Kommentare packen, nach jedem Druck auf „eval()“ wird das ganze gespeichert und versioniert.

Ich bin gespannt auf eure Lösungen!

Written by Michael Kliewe

März 11th, 2015 at 10:58 pm

Posted in PHP

Tagged with ,

12 Responses to 'Ein altes Navigationsmenu sortieren'

Subscribe to comments with RSS or TrackBack to 'Ein altes Navigationsmenu sortieren'.

  1. Bei einer Oracle-Datenbank erledigt man das ganz simpel mit connect by sowie level.
    http://www.datenbank-sql.de/oracle-hierarchie.htm

    Tobias Rohde

    11 Mrz 15 at 23:24

  2. Mal davon abgesehen, dass das Level umsonst ist, habe ich dir das mal schnell runter getippt bzw. copy paste von php.net

    function array_orderby()
    {
    $args = func_get_args();
    $data = array_shift($args);
    foreach ($args as $n => $field) {
    $tmp = array();
    foreach ($data as $key => $row)
    $tmp[$key] = $row[$field];
    $args[$n] = $tmp;
    }
    $args[] = &$data;
    call_user_func_array('array_multisort', $args);
    return array_pop($args);
    }
    function byTopId($items,$id) {
    $return = array();
    foreach($items as $item) {
    if($item[1] == $id) {
    $return[] = $item;
    }
    }
    if(count($return) > 0) {
    $return = array_orderby($return,4);
    }
    return $return;
    }
    function sortMenu($menu,$topid,&$return) {
    $items = byTopId($menu,$topid);
    foreach($items as $item) {
    $return[] = $item;
    sortMenu($menu,$item[0],$return);
    }
    }
    $return = array();
    sortMenu($menu,0,$return);
    var_dump($return);

    Juan Muerte Duarte Diaz

    12 Mrz 15 at 08:02

  3. Im Feld „title“ ist doch eh schon die Sortierreiehnfolge angegeben. Sortier doch einfach danach:

    SELECT title FROM tabelle ORDER BY SUBSTRING(title, LENGTH(title) – LOCATE(‚ ‚, REVERSE(title))+2)

    😉

    HutzenDuddel

    12 Mrz 15 at 10:21

  4. Nachtrag: Funktioniert aber nur solange, wie es weniger als 10 Einträge pro Ebene gibt.

    HutzenDuddel

    12 Mrz 15 at 10:49

  5. Die Idee von HutzenDuddel aufgreifend, aber rein in PHP, dafür funktioniert es auch mit >10 Einträgen pro Ebene:

    http://3v4l.org/sSsDC

    Daniel

    12 Mrz 15 at 16:07

  6. @Tobias: Schöne Lösung! Habe nur leider keine Oracle-Datenbank 😉

    @Juan: Deine Lösung funktioniert wunderbar, habe es gerade auch für 4 Level ausprobiert, klappt einwandfrei. Durch die Rekursion sollte es allgemeingültig sein.

    @HutzenDuddel + @Daniel: Der Titel darf nicht zur Sortierung verwendet werden. Der enthält hier nur zu Anschauungszwecken die Verschachtelungsstruktur als Zahlen, in den „richtigen“ Menupunkten sind diese Zahlen natürlich nicht vorhanden. Deshalb schrieb ich oben im Blogartikel „Die Sortierreihenfolge muss anhand der menuid, parentid, level und sortid berechnet werden.“
    Ganz so einfach ist es leider nicht 😉

    Michael Kliewe

    14 Mrz 15 at 12:09

  7. Nicht sehr performant, einfach der Weg über die Knotenstruktur …

    http://3v4l.org/B3SAD/

    Wolfgang

    2 Jun 15 at 18:13

  8. Etwas frickelig .. aber bestimmt ganz interessant 🙂

    https://3v4l.org/RuFPp

    steffen

    18 Aug 15 at 16:39

  9. T

    14 Okt 15 at 20:38

  10. Der Wurm ist ein Kindknoten vom Tiger, der Bär ist ein Kindknoten vom Wurm. Die Katze ist auch ein Kindknoten vom Tiger, hat aber die höhere sortid, muss also nach dem Wurm einsortiert werden.

    Merkst du eigentlich noch was?

    Durchfallman

    21 Okt 15 at 17:17

  11. Hier meine Version: https://3v4l.org/qPDZW

    Oliver

    23 Jan 16 at 07:57

  12. Da kannst du ja gleich alles kommasepariert in ein einziges Datenbankfeld packen…

    Bitte die Datenstruktur optimieren und nicht noch mehr schlechten Code herum bauen!

    Hier ein Einstieg:
    https://stackoverflow.com/questions/4048151/what-are-the-options-for-storing-hierarchical-data-in-a-relational-database#

    Max

    27 Mai 19 at 13:48

Leave a Reply

You can add images to your comment by clicking here.