Rabeneik: Multidimensionales Array sortieren

0 50

Multidimensionales Array sortieren

Rabeneik
  • php
  1. 0
    Tabellenkalk
    1. 0
      Rabeneik
      1. 1
        raketenhandbuchleser
  2. 0
    Raktenhandbuchleser
    1. 0
      Rabeneik
      1. 0
        Raktenhandbuchleser
        1. 0
          Rabeneik
  3. 1
    Rolf B
    1. 0
      Rabeneik
      1. 0
        Rolf B
        1. 0

          Multidimensionales Array sortieren: Neues Array

          Rabeneik
          1. 0
            Rolf B
          2. 0
            Raketenhandbuchleser
            1. 0

              Mist! (Korrektur)

              Raketenhandbuchleser
              1. 0
                Rabeneik
          3. 0
            Rolf B
            1. 0
              Raketenhandbuchleser
              1. 0
                Rabeneik
                1. 0
                  Raketenhandbuchleser
                  1. 0
                    Rabeneik
                    1. 0
                      Raketenhandbuchleser
            2. 0
              Rabeneik
              1. 0
                Rolf B
                1. 0
                  Rabeneik
                  1. 0
                    Raketenwissenschaftler
                    1. 0
                      Rabeneik
                      1. 0

                        Danke fürs Danke!

                        Raketenwissenschaftler
                        1. 0
                          Raketenwissenschaftler
                          • zur info
                    2. 0
                      😁😁
                      • humor
                    3. 1
                      dedlfix
                      1. 1
                        Rolf B
                        1. 0
                          Der Martin
                      2. 0

                        Vorschläge überprüfbar überprüft

                        Raketenwissenschaftler
                        1. 0

                          Messfehler entdeckt und korrigiert. Erneute Messung:

                          Raketenwissenschaftler
                          1. 0
                            Raketenwissenschaftler
                        2. 1
                          dedlfix
                          1. -1
                            Raketenwissenschaftler
                            1. 0
                              Rolf B
                              1. 0
                                Raketenwissenschaftler,
                                1. 1
                                  Rolf B
                                  1. 0
                                    Raketenphilosoph
                                    1. 1
                                      Julius
                                      1. 0

                                        Über CPUs „wandernder“ Prozess

                                        Raketenphilosoph
                                        1. 0
                                          Rolf B
                                          1. 2
                                            Raketenphilosoph
                                          2. 0

                                            (sich kloppende threads)

                                            Raketenspaßverteiler
                                            • humor
                            2. 0
                              Rabeneik
                              1. 0
                                Raketenwissenschaftler
  4. 0
    TS

Hallo,

ich habe ein Multiarray in php. Es ist wie folgt aufgebaut.

Array
(
    [0] => Array
        (
            [UID] => 5ea6c609473ab
            [Status] => RW
            [Prio] => 1
            [Prio2] => 1
            [Datum] => 06.02.2020
            [Menge] => 1.00
            [Textpos] => 
            [Bezeichnung] => 
            [Einzelpreis] => 15.00
            [Gesamtpreis] => 15.00
        )

    [1] => Array
        (
            [UID] => 5ea6c60947793
            [Status] => RW
            [Prio] => 1
            [Prio2] => 1
            [Datum] => 04.02.2020
            [Menge] => 1.00
            [Textpos] => 
            [Bezeichnung] => 
            [Einzelpreis] => 0.00
            [Gesamtpreis] => -
        )

    [2] => Array
        (
            [UID] => 5ea6c60947b7b
            [Status] => F
            [Prio] => 1
            [Prio2] => 1
            [Datum] => 03.02.2020
            [Menge] => 1.00
            [Textpos] => 
            [Bezeichnung] =>  
            [Einzelpreis] => 44.00
            [Gesamtpreis] => 44.00
        )

    [3] => Array
        (
            [UID] => 5ea6c60947b7b
            [Status] => Rabatt F
            [Prio] => 3
            [Prio2] => 1
            [Datum] => 
            [Menge] => 
            [Textpos] => 
            [Bezeichnung] => Rabatt 12.00 %
            [Einzelpreis] => -5.28
            [Gesamtpreis] => -5.28
        )

    [4] => Array
        (
            [UID] => 5ea6c60947b7b
            [Status] => Z
            [Prio] => 1
            [Prio2] => 2
            [Datum] => 06.02.2020
            [Menge] => 1.00
            [Textpos] => 
            [Bezeichnung] =>  
            [Einzelpreis] => 44.00
            [Gesamtpreis] => 44.00
        )

Das Array möchte ich nach folgenden Kriterien neu sortieren:

  1. nach Datum
  2. Die Elemente gleicher UID sollen zusammen bleiben
  3. nach PRIO sortiert
  4. nach Prio2 sortiert

Demnach müsste dann die Reihenfolge 2,3,1,0,4 dabei rauskommen.

Kann ich das über php-Funktionen so sortieren oder muss ich das Array hierfür durchlaufen? Wie mache ich das sinnvoll?

Rabeneik

  1. Hallo,

    Demnach müsste dann die Reihenfolge 2,3,1,0,4 dabei rauskommen.

    Das kann nix werden, da die 3 gar kein Datum hat…

    Gruß
    Kalk

    1. Hallo,

      Das kann nix werden, da die 3 gar kein Datum hat…

      Da ich das Array selber generiere, könnte ich da auch ein Fakedatum einsetzen.

      1. Da ich das Array selber generiere,

        Falls die Daten aus einer SQL-Datenbank entspringen solltest Du Dich über die ORDER BY-Klausel Deiner Datenbank informieren… Das ist einfacher und schneller als nachträglich zu sortieren.

  2. https://www.php.net/manual/de/function.usort.php

    Beispiel #2 hilft Dir zwar weiter, noch weiter würde Dir aber helfen, wenn Deine Array_Elemente besser aussähen:

    [Datum] => 06.02.2020
    [Gesamtpreis] => -
    
    [Datum] => '2020-02-06' # oder Unix-Time als Integer
    [Gesamtpreis] => 0
    

    Wenn das Array also bereinigt ist und keine Überraschungen mehr beinhaltet, kannst Du Dich an die Vergleichsfunktion machen...

    1. Beispiel #2 hilft Dir zwar weiter, noch weiter würde Dir aber helfen, wenn Deine Array_Elemente besser aussähen:

      [Datum] => 06.02.2020
      [Gesamtpreis] => -
      
      [Datum] => '2020-02-06' # oder Unix-Time als Integer
      [Gesamtpreis] => 0
      

      Wenn das Array also bereinigt ist und keine Überraschungen mehr beinhaltet, kannst Du Dich an die Vergleichsfunktion machen...

      Guter Hinweis, damit fange ich mal an. Die Daten kommen übrigens aus SQL, aber werden an vielen verschiedenen Stellen zusammengetragen, sodass ich nicnht vorsortieren kann.

      Rabeneik

      1. Die Daten kommen übrigens aus SQL, aber werden an vielen verschiedenen Stellen zusammengetragen, sodass ich nicht vorsortieren kann.

        Wenn die „verschiedenen Stellen“ Datentabellen in einer Datenbank oder in einem DBMS sind, dann solltest Du (wohl) dringend über JOINS nachlesen.

        Vielleicht auch über Views.

        Sind es verschiedene Datenbanken (im Sinne gänzlich verschiedener „Server“ bzw. Datenquellen) dann kann Dir womöglich etwas (aus meiner Sicht: wirklich) schreckliches wie „MS Power Query“ oder „Power Bi“ helfen.

        Besser als das wäre es aber aufzuräumen. Macht aber oft sehr viel Arbeit.

        1. Hallo,

          Wenn die „verschiedenen Stellen“ Datentabellen in einer Datenbank oder in einem DBMS sind, dann solltest Du (wohl) dringend über JOINS nachlesen.

          Danke für den Tip. Es kommen aber nicht alle Daten aus SQL oder einer DB.

          Rabeneik

  3. Hallo Rabeneik,

    1. nach Datum
    2. Die Elemente gleicher UID sollen zusammen bleiben

    Das widerspricht sich. Entweder ist das Datum führend, oder die UID.

    Gucken wir mal einen Extrakt deines Beispiels an.

    Nr UID Datum
    [0] 5ea6c609473ab 06.02.2020
    [1] 5ea6c60947793 04.02.2020
    [2] 5ea6c60947b7b 03.02.2020
    [3] 5ea6c60947b7b
    [4] 5ea6c60947b7b 06.02.2020

    Die Zeile 3 hat kein Datum, aber die gleiche UID wie die Zeile davor und dahinter. Die beiden scheinen in deiner Vorstellung eine logische Einheit zu bilden, und die soll beisammen bleiben.

    Aber du sagst, dass die erwartete Reihenfolge 2,3,1,0,4 sei. Das widerspricht ebenfalls deiner Vorgabe, denn warum darf Satz 4 von den Sätzen 2+3 getrennt werden, der hat doch die gleiche UID wie 2 und 3?

    Eine einfache Lösung kann darin bestehen, dass Du dein Array vor dem Sortieren durchgehst und in jeder Zeile, in der das Datum leer ist und die UID mit dem vorherigen Satz übereinstimmt, das Datum vom vorigen Satz überträgst. Danach sortierst Du nach Datum, UID, Prio und Prio2 - was mit usort und einem passenden Vergleichscallback lösen lässt.

    Aber bevor man wirklich zu etwas raten kann, solltest Du sehr viel präziser spezifizieren, wie deine Daten organisiert sind.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo,

      Gucken wir mal einen Extrakt deines Beispiels an.

      Nr UID Datum
      [0] 5ea6c609473ab 06.02.2020
      [1] 5ea6c60947793 04.02.2020
      [2] 5ea6c60947b7b 03.02.2020
      [3] 5ea6c60947b7b
      [4] 5ea6c60947b7b 06.02.2020

      Die Zeile 3 hat kein Datum, aber die gleiche UID wie die Zeile davor und dahinter. Die beiden scheinen in deiner Vorstellung eine logische Einheit zu bilden, und die soll beisammen bleiben.

      Aber du sagst, dass die erwartete Reihenfolge 2,3,1,0,4 sei. Das widerspricht ebenfalls deiner Vorgabe, denn warum darf Satz 4 von den Sätzen 2+3 getrennt werden, der hat doch die gleiche UID wie 2 und 3?

      Mea Culpa. Datensatz 4 sollte eine andere UID haben. Ich habe vergessen, sie zu ändern.

      Rabeneik

      1. Hallo Rabeneik,

        verstehe. Dann bleibt nun die Frage, ob ein leeres Datum so zu interpretieren ist, dass der Satz das gleiche Datum hat wie der vorherige Satz.

        Ist das so, dann trage dieses Datum als "fake datum", wie Du es nanntest, ein. Und wie der Raketenkollege schon sagte: das Datum im Array als yyyy-mm-dd zu formatieren macht das Leben leichter. Ggf. kannst Du das bereits in der SQL Query entsprechend aufbereiten.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo,

          hier also mein neues Array:

          Array
          (
              [0] => Array
                  (
                      [UID] => 5ea6c609473ab
                      [Status] => RW
                      [Prio] => 1
                      [Prio2] => 1
                      [Datum] => 2020-02-06
                      [Menge] => 1.00
                      [Textpos] => 
                      [Bezeichnung] => 
                      [Einzelpreis] => 15.00
                      [Gesamtpreis] => 15.00
                  )
          
              [1] => Array
                  (
                      [UID] => 5ea6c60947793
                      [Status] => RW
                      [Prio] => 1
                      [Prio2] => 1
                      [Datum] => 2020-02-04
                      [Menge] => 1.00
                      [Textpos] => 
                      [Bezeichnung] => 
                      [Einzelpreis] => 0.00
                      [Gesamtpreis] => 0.00
                  )
          
              [2] => Array
                  (
                      [UID] => 5ea6c60947b7b
                      [Status] => F
                      [Prio] => 1
                      [Prio2] => 1
                      [Datum] => 2020-02-03
                      [Menge] => 1.00
                      [Textpos] => 
                      [Bezeichnung] =>  
                      [Einzelpreis] => 44.00
                      [Gesamtpreis] => 44.00
                  )
          
              [3] => Array
                  (
                      [UID] => 5ea6c60947b7b
                      [Status] => Rabatt F
                      [Prio] => 3
                      [Prio2] => 1
                      [Datum] => 2020-02-03
                      [Menge] => 
                      [Textpos] => 
                      [Bezeichnung] => Rabatt 12.00 %
                      [Einzelpreis] => -5.28
                      [Gesamtpreis] => -5.28
                  )
          
              [4] => Array
                  (
                      [UID] => 5ea6c60947f63
                      [Status] => Z
                      [Prio] => 1
                      [Prio2] => 2
                      [Datum] => 2020-02-06
                      [Menge] => 1.00
                      [Textpos] => 
                      [Bezeichnung] =>  
                      [Einzelpreis] => 44.00
                      [Gesamtpreis] => 44.00
                  )
          
          

          Wie wende ich dann hier die Sortierfunktionen so an, dass meine Vorgaben erfüllt werden?

          Rabeneik

          1. Hallo Rabeneik,

            du hast Dir usort schon angeschaut?

            Für eine mehrstufige Sortierung vergleichst Du die Spalte mit der höchsten Sortier-Priorität zuerst.

            Bei Ungleichheit ist das Dein Ergebnis, bei Gleichheit machst Du mit der nächsten Priorität weiter.

            Rolf

            --
            sumpsi - posui - obstruxi
          2. 1. Schritt: UIDs zusammenhalten

            In einem erstem Schritt baust Du Deinen Array so um, dass die UIDs quasi zur Gruppe werden.

            $newArr = [];
            foreach ( $arr as $item ) {
               $uid = $item['UID'];
               unset( $item['UID'] );
               if ( ! isset ( $newArr[ $uid ] ) ) {
                  $newArr[ $item['UID'] ] = [];
               }
               $newArr[ $uid ][] = $item;
            }
            

            Es wäre nett, Du gäbest uns den neuen Array mit var_export() aus, dann können wir das Beispiel leichter nachbauen...

            1. Wenn ich `$item['UID'] kille, dann muss ich natürlich die vorher gemachte „Kopie“ $uid nutzen:

              $newArr = [];
              foreach ( $arr as $item ) {
                 $uid = $item['UID'];
                 unset( $item['UID'] );
                 if ( ! isset ( $newArr[ $uid ] ) ) {
                    $newArr[ $uid ] = [];
                 }
                 $newArr[ $uid ][] = $item;
              }
              
              1. Hallo,

                wenn ich Dich richtig verstehe, baust Du damit eine weitere Dimension ein. Und hast damit aber die Elemente schonmal nach UID zusammengefasst, die dann den Key ihrer Ebene bildet?

                Sorry, ich kann varexport nicht nutzen, weil ich selber im Moment nur dieses eine Beispielarray habe und nicht am Quellcode sitze.

                Müsste sowas hier rauskommen:

                Array
                (
                    [5ea6c609473ab] => Array
                        (
                            [0] => Array
                                (
                                    [Status] => RW
                                    [Prio] => 1
                                    [Datum] => 2020-02-06
                                    [Menge] => 1.00
                                    [Textpos] => 
                                    [Bezeichnung] =>  
                                    [Einzelpreis] => 15.00
                                    [Gesamtpreis] => 15.00
                                )
                
                        )
                
                    [5ea6c60947793] => Array
                        (
                            [0] => Array
                                (
                                    [Status] => RW
                                    [Prio] => 1
                                    [Datum] => 2020-02-04
                                    [Menge] => 1.00
                                    [Textpos] => 
                                    [Bezeichnung] => 
                                    [Einzelpreis] => 0.00
                                    [Gesamtpreis] => 0.00
                                )
                
                        )
                
                    [5ea6c60947b7b] => Array
                        (
                            [0] => Array
                                (
                                    [Status] => F
                                    [Prio] => 1
                                    [Datum] => 2020-02-03
                                    [Menge] => 1.00
                                    [Textpos] => 
                                    [Bezeichnung] =>  
                                    [Einzelpreis] => 44.00
                                    [Gesamtpreis] => 44.00
                                )
                
                            [1] => Array
                                (
                                    [Status] => Rabatt F
                                    [Prio] => 3
                                    [Datum] => 2020-02-03
                                    [Menge] => 
                                    [Textpos] => 
                                    [Bezeichnung] => Rabatt 12.00 %
                                    [Einzelpreis] => -5.28
                                    [Gesamtpreis] => -5.28
                                )
                
                        )
                
                    [5ea6c60947f63] => Array
                        (
                            [0] => Array
                                (
                                    [Status] => Z
                                    [Prio] => 1
                                    [Datum] => 2020-02-06
                                    [Menge] => 1.00
                                    [Textpos] => 
                                    [Bezeichnung] => 
                                    [Einzelpreis] => 44.00
                                    [Gesamtpreis] => 44.00
                                )
                
                        )
                )
                
          3. Hallo Rabeneik,

            du musst immer noch klarstellen, ob Sätze mit gleicher UID, aber auseinander liegendem Datum beisammen bleiben sollen oder nicht. Dass Du mir oben ausgewichen bist, indem Du einfach die UID geändert hast, führt nicht zur Klärung.

            Was der Raketenkollege vorschlägt, scheint darauf zu fußen, dass gleiche UID definitiv beieinander bleiben müssen, egal wie das Datum ist. Das würde aber nicht dazu passen, dass Du das Datum als höchste Sortierpriorität genannt hast.

            WIR wissen nicht was Du willst. Das weißt nur Du. "Specification By Example" hat in Fachbereichen zwar eine lange Tradition, aber genauso traditionell ist es, dass Projekte scheitern oder in immense Mehrkosten laufen, weil eben diese Beispiele unvollständig waren oder falsche Zusammenhänge daraus herausgelesen wurden.

            Technik ist einfach. Da genügt Handbuchlesen. Festzulegen, was die Technik tun soll, das ist die Herausforderung. Aber das musst Du festlegen, das können wir nicht. Wir können Dir Handbücher vorlesen 😉

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Was der Raketenkollege vorschlägt, scheint darauf zu fußen, dass gleiche UID definitiv beieinander bleiben müssen, egal wie das Datum ist.

              Genau so habe ich das verstanden. Denn sonst hätte er schreiben können:

              1. nach UID
              2. nach Datum
              3. nach PRIO
              4. nach Prio2
              

              Damit würden die UID übrigens automatisch zusammenbleiben. Hat er aber nicht, sondern:

                1.  nach Datum
                2.  Die Elemente gleicher UID sollen zusammen bleiben
                3.  nach PRIO sortiert
                4.  nach Prio2 sortiert
              

              Jetzt bin ich natürlich ein Genauheimer, aber ich würde hier erstmal strikt nach den UIDs gruppieren und dann ggf. sogar mehfach sortieren:

              Einmal die Teilarrays[UID] nach PRIO, Prio2. Dann den gesamten Array nach dem Datum der Teilarrays[UID]. Dafür fehlt mir noch eine Angabe: Soll das jüngste oder das älteste Datum der Teilarrays[UID] herangezogen werden?

              Wir können Dir Handbücher vorlesen 😉

              Ich hab nen Nickname für Dich: "Lichtunterdenscheffelsteller".

              1. Dafür fehlt mir noch eine Angabe: Soll das jüngste oder das älteste Datum der Teilarrays[UID] herangezogen werden?

                Die Einträge sollen chronologisch vom jüngsten Datum bis zum ältesten sortiert werden.

                1. Ok. Sätze mit gleicher UID haben auch immer daselbe Datum.

                  Die Einträge sollen chronologisch vom jüngsten Datum bis zum ältesten sortiert werden.

                  Also stumpf sortieren mit

                  1. nach Datum
                  2. nach UID
                  3. nach PRIO
                  4. nach Prio2
                  

                  Frage: Das sieht sehr stark nach nach einer „parametrisierten Versand- oder Herstellungspriorisierung“ aus.

                  Könnte es im Hinblick auf die weitere Programmgestaltung vorteilhaft sein, die zwangsweise Gruppierung nach den UIDs beizubehalten? Sonst war die sowohl „kostenlos“ als auch „umsonst“ (a.k.a. „für die Katz“).

                  1. Frage: Das sieht sehr stark nach nach einer „parametrisierten Versand- oder Herstellungspriorisierung“ aus.

                    Könnte es im Hinblick auf die weitere Programmgestaltung vorteilhaft sein, die zwangsweise Gruppierung nach den UIDs beizubehalten? Sonst war die sowohl „kostenlos“ als auch „umsonst“ (a.k.a. „für die Katz“).

                    Ja, das wäre schon sinnvoll. Aber warum fragst Du? Die läßt sich doch jederzeit wieder herstellen oder habe ich die Frage falsch verstanden?

                    1. Aber warum fragst Du? Die läßt sich doch jederzeit wieder herstellen oder habe ich die Frage falsch verstanden?

                      Ich hab viel mit Juristen zu tun. Bei denen lautet angeblich der erste Satz auf wirklich jede Frage, "Da kommt es auf allerhand an.". Das ist beim Programmieren nicht viel anders: Was überhaupt eine oder gar „die beste“ Lösung ist, hängt von vielen Nebenbedingungen ab.

                      Dein Problem selbst hab ich (wegen der nachgelieferten Sortierregeln) jetzt auf der Basis des ursprünglichen Array gelöst und den alsten und nicht mehr brauchbaren Umbau da als Kommentar stehen gelassen. Den kannst Du ggf. nach der Sortierung anwenden...

            2. Hallo Rolf,

              du musst immer noch klarstellen, ob Sätze mit gleicher UID, aber auseinander liegendem Datum beisammen bleiben sollen oder nicht. Dass Du mir oben ausgewichen bist, indem Du einfach die UID geändert hast, führt nicht zur Klärung.

              Ok. Sätze mit gleicher UID haben auch immer daselbe Datum. Durch meinen Fehler (copy+paste) war das nicht so, ich weiß.

              Was der Raketenkollege vorschlägt, scheint darauf zu fußen, dass gleiche UID definitiv beieinander bleiben müssen, egal wie das Datum ist.

              Ja, das ist auch so. Eben, weil das Datum dann auch identisch sein muss. Ich habe mal versucht, Raketenkolleges Funktion "anzuwenden".

              Rabeneik

              1. Hallo Rabeneik,

                Ok. Sätze mit gleicher UID haben auch immer daselbe Datum.

                A-HA! Da fand ein Wurm den Weg aus der Nase.

                In dem Fall würde ich Jörgs Gruppierung nach UID nicht verwenden, sondern stumpf nach Datum, UID, Prio und Prio2 sortieren.

                REPEAT
                   echo "du hast Dir usort schon angeschaut?"
                   $answer = $rabeneik->getAnswer()
                UNTIL $answer->makesSense()
                

                Rolf

                --
                sumpsi - posui - obstruxi
                1. Hallo Rolf,

                  REPEAT
                     echo "du hast Dir usort schon angeschaut?"
                     $answer = $rabeneik->getAnswer()
                  UNTIL $answer->makesSense()
                  

                  Habe ich gemacht, aber nicht wirklich verstanden.:-(

                  1. Der Trick bei usort und Kolleginnen ist, dass man einer selbst geschriebenen Vergleichsfunktion zwei Parameter mitgibt.

                    Die Vergleichsfunktion vergleicht beide:

                    Ist der erste (in den Beispielen $a) kleiner als wie zweite, so gubt diese Funktion -1 zurück: usort tut dann nichts.

                    Ist der erste (in den Beispielen $a) genau so groß als der zweite, so gibt diese Funktion "0" zurück. usort tut dann nichts.

                    Ist der erste (in den Beispielen $a) größer als der zweite, so gibt diese Funktion "1" zurück. Usort tauscht dann um.

                    Auf einer ganzen Reihe solcher Vergleichs- und Umtauschaktionen basieren alle Sortieralgorythmen.

                    Meine Vergleichsfunktion für usort macht im Prinzip genau das, was Rolf geschrieben hat: Wenn sich das datum nicht unterscheidet wird nach UID sortiert. Unterscheidet sich auch die nicht, dann nach Prio, dto nach Prio2.

                    Ich habe noch eine Hilfsfunktion geschrieben, welche anders die in den Beispielen im Handbuch wenigstens sowohl Strings als auch Zahlenwerte verträgt und mit dem dritten Parameter $invers eine andere Sortierreihenfolge ermöglicht (es werden dann einfach $a und $b vertauscht...)

                    <?php
                    $arr[0]['UID'] = '5ea6c609473ab';
                    $arr[0]['Status'] = 'RW';
                    $arr[0]['Prio'] = 1;
                    $arr[0]['Prio2'] = 1;
                    $arr[0]['Datum'] = '2020-06-02';
                    $arr[0]['Menge'] = 1.00;
                    $arr[0]['Textpos'] = NULL;
                    $arr[0]['Bezeichnung'] = NULL;
                    $arr[0]['Einzelpreis'] = 15.00;
                    $arr[0]['Gesamtpreis'] = 15.00;
                    
                    
                    $arr[1]['UID'] = '5ea6c60947793';
                    $arr[1]['Status'] = 'RW';
                    $arr[1]['Prio'] = 1;
                    $arr[1]['Prio2'] = 1;
                    $arr[1]['Datum'] = '2020-04-02';
                    $arr[1]['Menge'] = 1.00;
                    $arr[1]['Textpos'] = NULL;
                    $arr[1]['Bezeichnung'] = NULL;
                    $arr[1]['Einzelpreis'] = 0.00;
                    $arr[1]['Gesamtpreis'] = NULL;
                    
                    
                    $arr[3]['UID'] = '5ea6c60947793';
                    $arr[3]['Status'] = 'F';
                    $arr[3]['Prio'] = 1;
                    $arr[3]['Prio2'] = 2;
                    $arr[3]['Datum'] = '2020-04-02';
                    $arr[3]['Menge'] = 1.00;
                    $arr[3]['Textpos'] = NULL;
                    $arr[3]['Bezeichnung'] = NULL;
                    $arr[3]['Einzelpreis'] = 100.00;
                    $arr[3]['Gesamtpreis'] = NULL;
                    
                    /*
                    $newArr = [];
                    foreach ( $arr as $item ) {
                       $uid = $item['UID'];
                       unset( $item['UID'] );
                       if ( ! isset ( $newArr[ $uid ] ) ) {
                          $newArr[ $uid ] = [];
                       }
                       $newArr[ $uid ][] = $item;
                    }
                    */
                    echo "\n================================\n";
                    var_export( $arr );
                    echo "\n================================\n";
                    echo "Nach Sortieren:";
                    echo "\n================================\n";
                    function myCompare ($a, $b, $invers = false ) {
                    	if ( $invers ) {
                    		$c=$a; $a=$b; $b=$c; unset( $c );
                    	}
                    	if ( is_string( $a ) and is_string( $b ) ) {
                    		return strcmp( $a, $b );
                    	} elseif ( is_numeric( $a )  and is_numeric( $b ) ) {
                    		if ( $a == $b ) return 0;
                    		if ( $a <  $b ) return -1;
                    		if ( $a >  $b ) return 1;
                    	} 
                    	trigger_error( 'Nicht vorgesehener Datentyp in Funktion myCompare. Erlaubt sind string und numeric', E_USER_ERROR );
                    }
                    
                    
                    function compare_Datum_UID_Prio_Prio2 ( $a, $b ) {
                    	$invers['Datum'] = false;
                    	$invers['UID'] = false;
                    	$invers['Prio'] = true;
                    	$invers['Prio2'] = true;
                    	foreach ( [ 'Datum', 'UID', 'Prio', 'Prio2' ] as $itemProp ) {
                    		$r = myCompare( $a[$itemProp], $b[$itemProp], $invers[$itemProp] );
                    		if ( 0 != $r ) {
                    			return $r;
                    		}
                    	}
                    }
                    
                    usort($arr, 'compare_Datum_UID_Prio_Prio2' );
                    
                    var_export( $arr );
                    echo "\n================================\n";
                    

                    Meine Ausgaben:

                    ================================
                    array (
                      0 => 
                      array (
                        'UID' => '5ea6c609473ab',
                        'Status' => 'RW',
                        'Prio' => 1,
                        'Prio2' => 1,
                        'Datum' => '2020-06-02',
                        'Menge' => 1.0,
                        'Textpos' => NULL,
                        'Bezeichnung' => NULL,
                        'Einzelpreis' => 15.0,
                        'Gesamtpreis' => 15.0,
                      ),
                      1 => 
                      array (
                        'UID' => '5ea6c60947793',
                        'Status' => 'RW',
                        'Prio' => 1,
                        'Prio2' => 1,
                        'Datum' => '2020-04-02',
                        'Menge' => 1.0,
                        'Textpos' => NULL,
                        'Bezeichnung' => NULL,
                        'Einzelpreis' => 0.0,
                        'Gesamtpreis' => NULL,
                      ),
                      3 => 
                      array (
                        'UID' => '5ea6c60947793',
                        'Status' => 'F',
                        'Prio' => 1,
                        'Prio2' => 2,
                        'Datum' => '2020-04-02',
                        'Menge' => 1.0,
                        'Textpos' => NULL,
                        'Bezeichnung' => NULL,
                        'Einzelpreis' => 100.0,
                        'Gesamtpreis' => NULL,
                      ),
                    )
                    ================================
                    Nach Sortieren:
                    ================================
                    array (
                      0 => 
                      array (
                        'UID' => '5ea6c60947793',
                        'Status' => 'F',
                        'Prio' => 1,
                        'Prio2' => 2,
                        'Datum' => '2020-04-02',
                        'Menge' => 1.0,
                        'Textpos' => NULL,
                        'Bezeichnung' => NULL,
                        'Einzelpreis' => 100.0,
                        'Gesamtpreis' => NULL,
                      ),
                      1 => 
                      array (
                        'UID' => '5ea6c60947793',
                        'Status' => 'RW',
                        'Prio' => 1,
                        'Prio2' => 1,
                        'Datum' => '2020-04-02',
                        'Menge' => 1.0,
                        'Textpos' => NULL,
                        'Bezeichnung' => NULL,
                        'Einzelpreis' => 0.0,
                        'Gesamtpreis' => NULL,
                      ),
                      2 => 
                      array (
                        'UID' => '5ea6c609473ab',
                        'Status' => 'RW',
                        'Prio' => 1,
                        'Prio2' => 1,
                        'Datum' => '2020-06-02',
                        'Menge' => 1.0,
                        'Textpos' => NULL,
                        'Bezeichnung' => NULL,
                        'Einzelpreis' => 15.0,
                        'Gesamtpreis' => 15.0,
                      ),
                    )
                    ================================
                    
                    1. Hallo Raketenwissenschaftler,

                      Der Trick bei usort und Kolleginnen ist, dass man einer selbst geschriebenen Vergleichsfunktion zwei Parameter mitgibt.

                      Ich habe mich die letzte Stunde ausführlich damit beschäftigt. Es ist mir auch gelungen, ein Array zu sortieren. Aber meine Frage konnte ich so nicht lösen.

                      Die Vergleichsfunktion vergleicht beide:

                      Ist der erste (in den Beispielen $a) kleiner als wie zweite, so gubt diese Funktion -1 zurück: usort tut dann nichts.

                      Ist der erste (in den Beispielen $a) genau so groß als der zweite, so gibt diese Funktion "0" zurück. usort tut dann nichts.

                      Ist der erste (in den Beispielen $a) größer als der zweite, so gibt diese Funktion "1" zurück. Usort tauscht dann um.

                      Ging für mich aus der Doku erstmal nicht sofort hervor. Jetzt natürlich schon, danke für die Erklärung.

                      Meine Vergleichsfunktion für usort macht im Prinzip genau das, was Rolf geschrieben hat: Wenn sich das datum nicht unterscheidet wird nach UID sortiert. Unterscheidet sich auch die nicht, dann nach Prio, dto nach Prio2.

                      Ich habe noch eine Hilfsfunktion geschrieben, welche anders die in den Beispielen im Handbuch wenigstens sowohl Strings als auch Zahlenwerte verträgt und mit dem dritten Parameter $invers eine andere Sortierreihenfolge ermöglicht (es werden dann einfach $a und $b vertauscht...)

                      Sehr geil. Gerade die Inversfunktion ist sehr hilfreich. Die Stringfunktion ist für mich egal, aber als Grundgerüst für spätere Sortierungen werde ich sie mir behalten 😉

                      Sie funktioniert nicht nur in Deinem Beispiel, sondern auch in meinem Original, wie gewünscht! Danke für die Hilfe!

                      Interessant war auch, ich wußte gar nicht, dass man das Array in foreach ( [ 'Datum', 'UID', 'Prio', 'Prio2' ] as $itemProp ) { direkt übergeben kann ohne es in einer Variable zwischenzuspeichern.

                      Rabeneik

                      1. Hallo Rabeneik!

                        Also falls Du hier noch mitlesen solltest:

                        Die Vorschläge für die (Mikro)Optimierungen von dedlfix, Rolf B und Martin solltest Du Dir natürlich auf jeden Fall anschauen und überlegen, was davon Du übernehmen willst.

                        Ansonsten solltest man hier im Forum wohl nicht allzu genau auf die Bewertungen schauen. Die Technik des Bewertungssystems funktioniert wunderprächtig. Aber genau wie das mit den Typen ist, welche montags in der Zeitung stehen, vermögen manche nicht, diese in sinnigiger Weise zu benutzen. (Ich gehe aber davon aus, dass dedlfix, Rolf B oder Martin nicht dazu gehören).

                        1. Eine weitere Unsitte von manchen - es sind wohl diejenigen, deren Bewertungsverhalten ich nicht grundlos als „imponierend impulsiv, wohl gedankenlos oder (im schlimmsten Fall) absichtlich unangemessen und deshalb negative Reaktionen provozierend“ betrachte - ist es zweifellos, dass ebendiese eine - ausformulierte - Bewertung der (eigenen) „Bewertung“ nicht zu akzeptieren vermögen.

                          Ich jedenfalls bin in der Lage auf sachlichen Vortrag auch sachlich zu antworten ohne z.B. gleich „persönlich zu werden" (weshalb ich jetzt den Link zu einem aussagekräftigen Beispiel für das Folgende nicht setze) wie neulich erst durch eine Person mit guten Programmierkenntnissen aber grässlichem Kommunikationsverhalten und „auffällig geringer Frustrationstoleranz“ geschehen.

                          In diesem Sinne fühle ich mich durch die obige Bewertung nur in meinem Eindruck bestätigt.

                          Das das so sein wird, hätte man übrigens vorhersehen können. Wenn man denn weniger impulsiv handeln würde.

                          Hint: Ich weiß, was gleich passiert.

                    2. Dieser Beitrag wurde gelöscht: Sinnlosposting ohne Inhalt und Aussage
                    3. Tach!

                      Ich habe noch eine Hilfsfunktion geschrieben, welche anders die in den Beispielen im Handbuch wenigstens sowohl Strings als auch Zahlenwerte verträgt und mit dem dritten Parameter $invers eine andere Sortierreihenfolge ermöglicht (es werden dann einfach $a und $b vertauscht...)

                      Stattdessen könnte man auch beim Ergebnis das Vorzeichen wechseln. return $invers ? -$resultat : $resultat; Dann muss man nicht die beiden Datensätze mit einer zusätzlichen Hilfsvariable tauschen. Außerdem käme list($b, a) = [$a, $b]; ohne eine solche aus. Und bei numerischen Werten muss man nicht drei Vergleiche ausführen, sondern rechnet einfach $b - $a.

                      dedlfix.

                      1. Hallo dedlfix,

                        an der Vergleichsfunktion ist einiges im Argen. Und nicht nur da.

                        • die Schleife für den Aufbau von $newArr ist sehr merkwürdig gebaut.
                        • unnötiges Swapping, wie schon von Dir genannt
                        • unnötiges unset einer lokalen Variablen, die verdampft am Funktionsende sowieso
                        • unnötig aufwändiger Vergleich im numeric Zweig
                        function myCompare($a, $b, $invers = false ) {
                          
                          $inv = $invers ? -1 : 1;
                          if ( is_string( $a ) and is_string( $b ) ) {
                            return strcmp( $a, $b ) * $inv;
                          } elseif ( is_numeric( $a )  and is_numeric( $b ) ) {
                            if ( $a == $b ) return 0;
                            if ( $a <  $b ) return -$inv;
                            return $inv;
                            // oder: return ($a == $b) ? 0 : (($a < $b) ? -$inv : $inv);
                            // oder (PHP 7): return ($a <=> $b) * $inv;
                          } 
                          trigger_error( 'Nicht unterstützter Vergleich von '.gettype($a).' und '.gettype($b).' in Funktion myCompare. Erlaubt sind string und numeric', E_USER_ERROR );
                        }
                        

                        Generell würde ich aber einen Sortier-Callback nicht unnötig mit Helpern und Abstraktion belasten. Wenn's irgendwo schnell gehen muss, dann dort. Das bedeutet: Typen prüft man vor dem Sortieren und nicht im Callback, denn ein Sortieralgorithmus packt die Einträge im Array mehrfach an. Was auch lohnt, ist die Frage nach der PHP Version: Ist es 7 oder mehr? Denn dann haben wir den Spaceship-Operator, der zum Sortieren sehr nützlich ist.

                        function compare_Datum_UID_Prio_Prio2 ( $a, $b ) {
                          $result = $a['Datum'] <=> $b['Datum'];
                          if ($result != 0) return $result;
                        
                          $result = $a['UID'] <=> $b['UID'];
                          if ($result != 0) return $result;
                        
                          $result = $b['Prio'] <=> $a['Prio'];    // invers!
                          if ($result != 0) return $result;
                        
                          return $b['Prio2'] <=> $a['Prio2'];    // invers!
                        }
                        

                        Diesen Code könnte man noch weiter eindampfen, aber dann wird er schwer lesbar.

                        Ohne Spaceship könnte man über einen Compare-Helper nachdenken, oder es doch stumpf runterprogrammieren. Funktionsaufrufe sind vor PHP 7 deutlich langsamer gewesen.

                        function compare_Datum_UID_Prio_Prio2 ( $a, $b ) {
                          if ($a['Datum'] < $b['Datum']) return -1;
                          if ($a['Datum'] > $b['Datum']) return 1;
                        
                          if ($a['UID'] < $b['UID']) return -1;
                          if ($a['UID'] > $b['UID']) return 1;
                        
                          if ($a['Prio'] < $b['Prio']) return 1;   // Invers!
                          if ($a['Prio'] > $b['Prio']) return -1;
                        
                          if ($a['Prio2'] < $b['Prio2']) return 1;   // Invers!
                          if ($a['Prio2'] > $b['Prio2']) return -1;
                        
                          return 0;
                        }
                        

                        Nochmal zurück zum ersten Punkt: die Schleife für den Aufbau von $newArr ist sehr merkwürdig gebaut.

                        • Ein unset auf das foreach-Item funktioniert nicht (und ist mutmaßlich auch unnötig), wegen des copy-on-write Verhaltens von PHP. Man müsste schon über eine Referenz iterieren: foreach ($arr as &$item). Dann wirken sich die unset in $arr aus.
                        • $newArr[ $uid ] = []; ist unnötig, wie beim Erstellen des Testdaten-Arrays $arr gezeigt wird. PHP legt bei $newArr[ $uid ][] = $item; automatisch einen Array-Eintrag an.

                        Rolf

                        --
                        sumpsi - posui - obstruxi
                        1. Hallo,

                          Was auch lohnt, ist die Frage nach der PHP Version: Ist es 7 oder mehr? Denn dann haben wir den Spaceship-Operator, der zum Sortieren sehr nützlich ist.

                          dessen Sinn leuchtet mir nicht ganz ein, denn so wie ich die Beschreibung verstehe, ist $a<=>$b im Wesentlichen äquivalent zu $a-$b, da das PHP-Manual nichts zum genauen Wert sagt, den dieser Operator liefert.

                          function compare_Datum_UID_Prio_Prio2 ( $a, $b ) {
                            $result = $a['Datum'] <=> $b['Datum'];
                            if ($result != 0) return $result;
                          
                            $result = $a['UID'] <=> $b['UID'];
                            if ($result != 0) return $result;
                          
                            $result = $b['Prio'] <=> $a['Prio'];    // invers!
                            if ($result != 0) return $result;
                          
                            return $b['Prio2'] <=> $a['Prio2'];    // invers!
                          }
                          

                          Ah, ich ahne etwas: Der Spaceship-Operator ist auch auf Strings anwendbar?
                          Okay, dann ist $a-$b als Ersatz natürlich Essig.

                          Live long and pros healthy,
                           Martin

                          --
                          Ich stamme aus Ironien, einem Land am sarkastischen Ozean.
                      2. Moin Dedlfix:

                        Deine Vorschläge lesen sich, eigentlich logisch. Aber wie das so ist, sind „Glaube“ und „Messen“ für den Tekki und den Theologiestudent jeweils ganz verschiedene Begriffe. Ich messe wie folgt:

                        <?php
                        
                        $z=1000000;
                        
                        for ( $i=0; $i<$z; $i++ ) {
                        	$a[$i] = sin($i);
                        	$b[$i] = cos($i);
                        }
                        
                        function tausch_rakete( $a, $b ) {
                        	$c = ( $b - $a );
                        }
                        $s = microtime( true );
                        for( $i=0; $i<$z; $i++ ) {
                          tausch_rakete( $a[$i], $b[$i] );
                        }
                        echo "tausch_rakete:\t" . ( microtime( true ) - $s )  . PHP_EOL;
                        
                        function tausch_dedlfix( $a, $b ) {
                        	list($a, $b) = [ $b, $a ];
                        }
                        $s = microtime( true );
                        for( $i=0; $i<$z; $i++ ) {
                          tausch_dedlfix( $a[$i], $b[$i] );
                        }
                        echo "tausch_dedlfix:\t" . ( microtime( true ) - $s ) . PHP_EOL;
                        
                        function cmp_rakete( $a, $b ) {
                          if ($a > $b ) return -1;
                          if ($a < $b ) return 1;
                          return 0;
                        }
                        $s = microtime( true );
                        for( $i=0; $i<$z; $i++ ) {
                          cmp_rakete( $a[$i], $b[$i] );
                        }
                        echo "cmp_rakete:\t" . ( microtime( true ) - $s )  . PHP_EOL;
                        
                        function cmp_dedlfix( $a, $b ) {
                          return ( $b - $a );
                        }
                        $s = microtime( true );
                        for( $i=0; $i<$z; $i++ ) {
                          cmp_dedlfix( $a[$i], $b[$i] );
                        }
                        echo "cmp_dedlfix:\t" . ( microtime( true ) - $s )  . PHP_EOL;
                        

                        … und erhalte diese bzw. solche Ergebnisse:

                        Ausgaben auf einem System mit „AMD Ryzen 7 2700 Eight-Core Processor“ und „PHP 7.2.24-0ubuntu0.18.04.4 (cli) (built: Apr 8 2020 15:45:57) ( NTS )“

                        tausch_rakete:  0.74383616447449
                        tausch_dedlfix: 0.92750906944275
                        cmp_rakete:     0.74426603317261
                        cmp_dedlfix:    0.71443104743958
                        
                        

                        Ausgaben auf einem System mit „Cortex-A72“ und „PHP 7.4.4 (cli) (built: Mar 20 2020 14:30:40) ( NTS )“

                        tausch_rakete:  0.17790603637695
                        tausch_dedlfix: 0.350172996521
                        cmp_rakete:     0.18490481376648
                        cmp_dedlfix:    0.16062998771667
                        
                        

                        Fazit:

                        Tatsächlich! Bezüglich des Vergleiches erscheint Deine Lösung also als etwas performanter.

                        1. Und wie das miit dem Überprüfen so ist, findet man da selbst auch Fehler. Hier lag er in der Funktion tausch_rakete(), die bei Copy & Paste mit falschem Inhalt versehen wurde:

                          function tausch_rakete( $a, $b ) {
                          	$c = ( $b - $a );
                          }
                          

                          Korrigiertes Skript:

                          <?php
                          
                          $z=1000000;
                          
                          for ( $i=0; $i<$z; $i++ ) {
                          	$a[$i] = sin($i);
                          	$b[$i] = cos($i);
                          }
                          
                          function tausch_rakete( $a, $b ) {
                          	$c = $a; $a = $b; $b = $c; unset( $c );
                          }
                          $s = microtime( true );
                          for( $i=0; $i<$z; $i++ ) {
                              tausch_rakete( $a[$i], $b[$i] );
                          }
                          echo "tausch_rakete:\t" . ( microtime( true ) - $s )  . PHP_EOL;
                          
                          function tausch_dedlfix( $a, $b ) {
                          	list($a, $b) = [ $b, $a ];
                          }
                          $s = microtime( true );
                          for( $i=0; $i<$z; $i++ ) {
                              tausch_dedlfix( $a[$i], $b[$i] );
                          }
                          echo "tausch_dedlfix:\t" . ( microtime( true ) - $s ) . PHP_EOL;
                          
                          function cmp_rakete( $a, $b ) {
                          		if ($a > $b ) return -1;
                          		if ($a < $b ) return 1;
                          		return 0;
                          }
                          $s = microtime( true );
                          for( $i=0; $i<$z; $i++ ) {
                              cmp_rakete( $a[$i], $b[$i] );
                          }
                          echo "cmp_rakete:\t" . ( microtime( true ) - $s )  . PHP_EOL;
                          
                          
                          function cmp_dedlfix( $a, $b ) {
                          		return ( $b - $a );
                          }
                          $s = microtime( true );
                          for( $i=0; $i<$z; $i++ ) {
                              cmp_dedlfix( $a[$i], $b[$i] );
                          }
                          echo "cmp_dedlfix:\t" . ( microtime( true ) - $s )  . PHP_EOL;
                          

                          Messung auf einem System mit „AMD Ryzen 7 2700 Eight-Core Processor“ und „PHP 7.2.24-0ubuntu0.18.04.4 (cli) (built: Apr 8 2020 15:45:57) ( NTS )“:

                          tausch_rakete:	0.83518505096436
                          tausch_dedlfix:	0.90218114852905
                          cmp_rakete:	    0.7413489818573
                          cmp_dedlfix:    0.68741798400879
                          

                          Ausgaben auf einem System mit „Cortex-A72“ und „PHP 7.4.4 (cli) (built: Mar 20 2020 14:30:40) ( NTS )“:

                          tausch_rakete:	0.83518505096436
                          tausch_dedlfix:	0.90218114852905
                          cmp_rakete:	    0.7413489818573
                          cmp_dedlfix:    0.68741798400879
                          
                          

                          Das bereits gezogene Fazit "Tatsächlich! Bezüglich des Vergleiches erscheint Deine Lösung also als etwas performanter." ist trotz des groben Messfehlers richtig.

                          1. Copy & Paste ist eine echte Kunst...

                            Ausgaben auf einem System mit „Cortex-A72“ und „PHP 7.4.4 (cli) (built: Mar 20 2020 14:30:40) ( NTS )“:

                            tausch_rakete:	0.31693887710571
                            tausch_dedlfix:	0.35032296180725
                            cmp_rakete:	    0.18891501426697
                            cmp_dedlfix:    0.1622211933136
                            
                            
                        2. Tach!

                          Deine Vorschläge lesen sich, eigentlich logisch. Aber wie das so ist, sind „Glaube“ und „Messen“ für den Tekki und den Theologiestudent jeweils ganz verschiedene Begriffe. Ich messe wie folgt:

                          Schön, dass du das auf Performance prüfst. Aber solch einen Messaufbau halte ich nicht für praxisrelevant.

                          $z=1000000;
                          

                          Es ist üblich, eine sehr hohe Zahl von Schleifendurchläufen herzunehmen, um ein Messergebnis für derartige Performancetests zu bekommen, dass sich vom Grundrauschen unterscheidet.

                          Eine Million Datensätze sortiert man besser unter Verwendung eines Index im DBMS und nicht in PHP. Zudem wird man mit PHP kaum eine solche hohe Anzahl an Datensätzen zum Client durchschaufeln. Da setzt man schon bei deutlich kleineren Mengen Paging ein, um die dem Anwender auf einmal präsentierte Menge klein zu halten. Somit ist auch die zu verarbeitende Menge kleiner und der Performanceunterschied noch weniger von Bedeutung.

                          Meine Antwort sollte nur Alternativen zum Code aufzeigen. Und der Spaceship-Operator, den ich nicht auf dem Schirm hatte, räumt da gleich noch mehr auf. Auf Performance bezog ich mich nicht, da ist für den Fall kein Blumentopf zu gewinnen.

                          dedlfix.

                          1. Tach!

                            Post!

                            Eine Million Datensätze sortiert man besser unter Verwendung eines Index im DBMS und nicht in PHP.

                            Wem sagst Du das (seufz)? Die einfache, bequeme und sichere Verwendung einer SQL-Datenbank war einer meiner ersten Vorschläge... (und ich bin noch immer der von mir geäußerten Meinung, dass es die beste Lösung wäre, die multiblen Datenquellen aufzuräumen. Übrigens vor allem weil solche Datenbestände horizontal und vertikal wachsen.

                            Schön, dass du das auf Performance prüfst. Aber solch einen Messaufbau halte ich nicht für praxisrelevant.

                            Nun ja. Das ist so, wie es CK über Bewertungsfunktion schrieb: „Es ist das beste, was wir haben.“ Aus Deinem Satz „Dann muss man nicht die beiden Datensätze mit einer zusätzlichen Hilfsvariable tauschen.“ hab ich halt die Unterstellung einer mießen Performance vermutet. Jetzt weiß ichs anders.

                            Zudem wird man mit PHP kaum eine solche hohe Anzahl an Datensätzen zum Client durchschaufeln. Da setzt man schon bei deutlich kleineren Mengen Paging ein

                            Was, so ganz nebenher, die vorherige(sic!) Sortierung erfordert…

                            Und der Spaceship-Operator, den ich nicht auf dem Schirm hatte, räumt da gleich noch mehr auf.

                            Das ist richtig. Hätte ich den „auf dem Schirm gehabt“ (Man muss sowas nicht nur wissen, es muss einem außerdem auch noch einfallen!) dann hätte ich den sicherlich gebraucht.

                            Meine Antwort sollte nur Alternativen zum Code aufzeigen.

                            Nun, mein Code sollte nicht nur das Problem an sich lösen sondern auch zeigen, wie man das machen kann. Klar ist er (auch deshalb) "nicht in allen Punkten vollendet elegant“ - aber er hat das Teilziel, dass dem TO die Nutzung der Funktion usort nebst der erforderlichen callback-Funktion klar wird, offensichtlich erfüllt. Ich denke, ich hab den TO bezüglich seines Ansinnens und seiner Kenntnisse durchaus richtig eingeschätzt: Der lernt manches auf die selbe Art wie ich und hat sogar die selben Schwierigkeiten: Ich weiß noch als was für eine „fürchterhafterliche Raketenwissenschaft“ mir die Chose mit den „Callback-Funktionen“ dereinst erschien.

                            Übrigens fühle ich mich vor allem deswegen so „angepisst“, weil $irgendwer (wen ich alles - auf Basis meiner Meinung - ausschließe habe ich schon geschrieben und ich bin außerdem nicht doof), der in diesem Therad nichts beigetragen hatte, einfach mal daherkommt und - ohne einen handfesten und dieses rechtfertigenden Grund zu haben - genau die Antwort abwertet, die der eigentliche Fragesteller kurz vorher nicht nur einfach mal gelobt hatte sondern auch beschrieb, was er daraus gelernt hatte.

                            1. Hallo Raketenwissenschaftler,

                              vielleicht hast Du das Minus ja für die "algorythmen" bekommen 😉. Oder für den komplexen Code - keine Ahnung. Jedenfalls hast Du die Idee der Sort-Callbacks gut erlärt und damit eher ein + als ein - verdient.

                              Ich hatte noch ein paar Messreihen gemacht mit deinem Flexi-Konstrukt und meiner Hardcode-Version, weil ich wissen wollte, wie teuer dein Konstrukt kommt. Und ja, es ist teuer, der Sort dauert dreimal so lange. Funktionsaufrufe machen PHP keinen Spaß, vor allem in PHP 5. PHP 7 ist signifikant besser optimiert. Dein unset $c ist nur unnötig, aber stört die Performance nicht.

                              Keine Ahnung wo das Posting geblieben ist, hab vielleicht vergessen "Senden" zu drücken. Gelöscht wurde es nicht, das sähe man.

                              Rolf

                              --
                              sumpsi - posui - obstruxi
                              1. PHP 7 ist signifikant besser optimiert.

                                Ist Dir an meinen Testergebnissen aufgefallen, dass PHP 7.4.4 auf dem formal um Klassen langsameren Raspi 4b+ mit Cortex-A72_Prozessor 1 Mio (triviale) Funktionsaufrufe in etwa 1/5 der Zeit schafft die PHP 7.2.24 auf dem „großen“ Rechner mit „AMD Ryzen 7 2700 Eight-Core Processor“ für den gleichen Job benötigt?

                                Schon da ist das „signifikant“ geradezu ein Euphemismus. Ich möchte das gar mehr auf identischen CPUs und schon gar nicht mit PHP 5.x vergleichen...

                                1. Hallo Raketenwissenschaftler,,

                                  nein, hab ich nicht drauf geachtet. Ich bin nicht so firm in Prozessortypen.

                                  Ich gehe davon aus, dass PHP für einen Request per Default single threaded operiert und die Anzahl der Kerne damit egal ist.

                                  Für die single-core Performance kann es verschiedene Gründe geben, außer der PHP Version auch die Qualität des Compilers der jeweiligen Plattform. Um die Verbesserungen in PHP Performance beurteilen zu können, solltest Du auf einer Maschine unterschiedliche PHP Versionen vergleichen.

                                  Ansonsten - Rrrrespekt, Rrraspi 😀

                                  Rolf

                                  --
                                  sumpsi - posui - obstruxi
                                  1. Ich gehe davon aus, dass PHP für einen Request per Default single threaded operiert und die Anzahl der Kerne damit egal ist.

                                    Das kann ich bestätigen. Ich sortiere schon einige (12) Minuten lang mit einem PHP-Skript knapp 6 Mio (aus zwei Listen mit Vor- und Nachnamen) zufällig zusammengebaute Namen nach allen Regeln der Kunst der Telefonbuchsortierung - also auch der Behandlung von Umlauten, Titeln und Namenszusätzen ("bibliographischen Ordnungsregeln DIN 31638")

                                    • 1 Thread, der über die Kerne geschoben wird um den Prozessor nicht nur an einer Stelle so schön warm zu machen:

                                    1. Hallo Raketenphilosoph,

                                      • 1 Thread, der über die Kerne geschoben wird um den Prozessor nicht nur an einer Stelle so schön warm zu machen:

                                      Ich bin mir nicht sicher, ob der Scheduler den PHP-Prozess deswegen öfter einen anderen CPU-Kern zuweist (kontraproduktiv ist es jedenfalls nicht), aber er weist ohnehin nicht ein und dem selben Prozess immer den gleichen CPU-Kern zu.

                                      Vor allem müsste PHP das Skript dann irgendwie Threadsicher bekommen. Ich bin mir nicht sicher, ob das so einfach automatisiert und ohne Zutun des Programmierers gehen würde. Und selbst wenn PHP selbst von sich aus einiges parallelisieren könnte, würde der Overhead vermutlich das Performance-Extra auffressen.

                                      Ansonsten muss man halt selbst tätig werden und die pthreads-PHP-Erweiterung benutzen.

                                      Gruß
                                      Julius

                                      1. (Über CPUs „wandernder“ Prozess)

                                        Ich bin mir nicht sicher, ob der Scheduler den PHP-Prozess deswegen öfter einen anderen CPU-Kern zuweist

                                        Ich hab jetzt die Quelle nicht zur Hand, aber das geschieht nicht nur mit dem PHP-Prozess.

                                        Aller paar Sekunden hoppeln lang laufende und die CPU gut beschäftigende Prozesse auf einen anderen Kern, um den Prozessor nicht durch eine starke punktuelle Erwärmung mechanisch zu belasten. Das gilt für alle hier verfügbaren Architekturen. (Intel, AMD64, ARM). Man kann mit Tools wie htop oder xosview dabei zusehen.

                                        Wenn ich Theads will kann ich ja mehrere Skripte mittels php -s $PORT starten und zwischen diesen via cUrl oder über das Dateisystem kommunizieren - wodurch die CPU garantiert immmer gleichmäßig hoch belastet wird :-)

                                        Im Hinblick dessen, wozu PHP eigentlich gedacht und gemacht ist werde ich das aber „eher nicht weiterverfolgen“, es also dabei belassen, dass die vielen kurz laufenden PHP Prozesse vom Webserver gestartet und vom OS der CPU „aufgedrückt“ werden.

                                        BTW. Das Sortieren der 5,59 Mio Namen/Vornamen/Titel (78 MB als CSV) nach den Telefonbuchregeln hat gestern volle 34 Minuten (auf dem „fetten“ AMD Ryzen 7 2700) bzw. 55 Minuten (auf dem Cortex-A72/Raspberry 4B+) gedauert. Einerseits bin ich vom Raspi noch einmal mehr begeistert, andererseits muss ich wohl einiges zulasten des Speicherverbrauchs optimieren; Da sind auf Grund der Anforderungen der Telefonbuchsortierung und DIN 31638 eine Menge Stringoperationen, die vor jedem eigentlichen Vergleich gemacht werden. Also längst nicht nur 5,59 Mio mal: das ist natürlich eine enorme Verschwendung.

                                        Aber, da die Sortierung selbst offenbar läuft und alle Härtests fehlerfrei überstanden hat sollte das „nur noch Arbeit“ sein.

                                        1. Hallo Raketenphilosoph,

                                          ich glaube nicht, dass das Hoppeln unbedingt mit Vorsatz geschieht. Es mag sein - muss aber nicht.

                                          Dein Computer führt hunderte von Threads aus, und da er nur 8 Kerne hat, kloppen die sich darum. Das kann der Fragmentierungswächter der Festplatte sein, der Maustreiber, da läuft ja massig im Hintergrund.

                                          Dein PHP Prozess ist einer von vielen in diesem Gewusel, und vermutlich hast Du ihn nicht auf "galactic important priority" gestellt. Darum wird er regelmäßig unterbrochen, weil irgendein anderer Thread rumnervt und was abhaben will. Es kann auch der virtuelle Speicher sein, auch wenn genug RAM da ist, geht zumindest unter Windows der Zähler für Seitenfehler regelmäßig hoch.

                                          Nach solchen Unterbrechungen landet dein PHP Thread ganz normal in der ready-queue des Task Schedulers und bekommt den nächsten freien Kern.

                                          Du KÖNNTEST natürlich auch testen, ob Du ein Loch ins Kühlblech brennen kannst, wenn Du PHP auf einen Kern fixierst. Da gibt's so Flags für die CPU Affinität ("Zugehörigkeit festlegen" im Task Manager eines deutschen Win10).

                                          Rolf

                                          --
                                          sumpsi - posui - obstruxi
                                          1. Meine ursprüngliche Quelle war mit Sicherheit was deutsches, vermutlich heise.de. Die finde ich aber aktuell nicht. Habe aber eine andere Quelle gefunden. DTM bzw. TM oder nennt sich das (wenns denn noch OS-basierend ist)

                                            Thread Migration (TM) also known as core hopping is a real time os based DTM technique. TM reduce the CPU-temperature by migrating core tasks "threads" from one overhated core to another core.

                                            (Automatisch übersetzt:)

                                            Die Thread-Migration (TM), auch als Core-Hopping bezeichnet, ist eine Echtzeit-OS-basierte DTM-Technik. TM reduziert die CPU-Temperatur, indem Kernaufgaben "Threads" von einem überhitzten Kern auf einen anderen Kern migriert werden.

                                            Das zitierte Buch ist aus 2011:

                                            https://books.google.de/books?id=f-GdDwAAQBAJ&pg=PA380&lpg=PA380&dq=cpu+threads+change+cores+thermal+purpose&source=bl&ots=yaD6OElu73&sig=ACfU3U19ruMilZbHllu7PPAe27T2oUoZ2A&hl=de&sa=X&ved=2ahUKEwjzyZqSuI3pAhVHDuwKHVuPCr8Q6AEwDnoECAsQAQ#v=onepage&q=cpu threads change cores thermal purpose&f=false, Seite 380, letzter Absatz.

                                            Mit "thread hopping core thermal temperature" als Suchbegriffen zeigt sich dann schnell, dass das Thema auch aktuell stark beforscht wird (im „Augenblick“ wohl hinsichtlich der Verteilung und also des Hoppings bei unterschiedlich schnellen Cores auf einem Prozessor und im Zusammenspiel mit dem Heruntertakten bei Überhitzung). Dann stoße ich da noch auf Begriffe wie “round robin“ (Das ist wohl das, was ich mit htop/xosview sehe.)

                                          2. Dein Computer führt hunderte von Threads aus, und da er nur 8 Kerne hat, kloppen die sich darum

                                            Auslastungsanzeige in htop

                                            Ich glaube, die spezielle Form des „Kloppens“ nennt sich „ideln“. Und der Schiedsrichter namens „scheduler“ ist genau so gelangweilt wie die Mehrzahl der Teilnehmer. Die wieder stehen auf dem Spielfeld rum, motzen und würden gerne wissen, worin sich DAS denn bitte GENAU vom Herumsitzen auf der Ersatzbank unterscheidet. Der Kommentator hatte auch schon besser zu tun.

                            2. Hallo,

                              Nun, mein Code sollte nicht nur das Problem an sich lösen sondern auch zeigen, wie man das machen kann. Klar ist er (auch deshalb) "nicht in allen Punkten vollendet elegant“ - aber er hat das Teilziel, dass dem TO die Nutzung der Funktion usort nebst der erforderlichen callback-Funktion klar wird, offensichtlich erfüllt. Ich denke, ich hab den TO bezüglich seines Ansinnens und seiner Kenntnisse durchaus richtig eingeschätzt: Der lernt manches auf die selbe Art wie ich und hat sogar die selben Schwierigkeiten: Ich weiß noch als was für eine „fürchterhafterliche Raketenwissenschaft“ mir die Chose mit den „Callback-Funktionen“ dereinst erschien.

                              Ich möchte das mal eben bestätigen. Dein Code war genau, was ich brauchte, um usort zu verstehen. Hier war "weniger" (mit Verlaub, so die anderen Lösungen noch besser sind) für mich mehr.

                              Rabeneik

                              1. Ich möchte das mal eben bestätigen. Dein Code war genau, was ich brauchte, um usort zu verstehen. Hier war "weniger" (mit Verlaub, so die anderen Lösungen noch besser sind) für mich mehr.

                                Rabeneik

                                Danke. Das hab ich heute „irgendwie“ gebraucht.

  4. Hello,

    Alternative:

    das sieht nach einem Warenkorb aus.
    Wieso steht der nicht in einer (temporären) Tabelle des DBMS?

    Dann müsstest Du dir um die Sortierung keine komplizierten Gedanken machen und der WK wäre nicht flüchtig. Wenn der Kunde nach einer Pause wiederkommt, kann er entweder weitermachen, oder den alten Versuch löschen.

    Glück Auf
    Tom vom Berg

    --
    Es gibt nichts Gutes, außer man tut es!
    Das Leben selbst ist der Sinn.