ebody: Assoziatives, mehrdimensionales Array sortieren

Hallo,

ich hoffe "Assoziatives, mehrdimensionales Array" ist für dieses Array die richtige Bezeichnung?

Um zu verstehen, wie man ein solches Array sortieren kann, verwende ich ein kleines, grobes Beispiel Array. Es soll nach der Marke (alphabetisch aufsteigend) sortiert werden und die Schlüssel der Marke, also die Modelle sollen ebenfalls (alphabetisch aufsteigend) sortiert werden.

Aktuelles Array:

$autos = array(
    "Porsche" => array(						// Marke
			"911 Blau" => array(				// Modell
				"Farbe" => "Blau",
				"Preis" => "70.000"
			),
			"Cayenne Schwarz" => array(	//Modell
				"Farbe" => "Schwarz",
				"Preis" => "80.000"
			)
		),
    "Dacia" => array(							// Marke
			"Logan Blau" => array(			//Modell
				"Farbe" => "Blau",
				"Preis" => "10.000"
			),
			"Logan Schwarz" => array(		//Modell
				"Farbe" => "Schwarz",
				"Preis" => "12.000"
			),		
			"Duster Blau"  => array(		//Modell
				"Farbe" => "Blau",
				"Preis" => "10.000"
			)
		)
);

So soll es nach der Sortierung aussehen:

$autos = array(
    "Dacia" => array(							// Marke
			"Duster Blau"  => array(		//Modell
				"Farbe" => "Blau",
				"Preis" => "10.000"
			),			
			"Logan Blau" => array(			//Modell
				"Farbe" => "Blau",
				"Preis" => "10.000"
			),
			"Logan Schwarz" => array(		//Modell
				"Farbe" => "Schwarz",
				"Preis" => "12.000"
			)		
		),
    "Porsche" => array(						// Marke
			"911 Blau" => array(				// Modell
				"Farbe" => "Blau",
				"Preis" => "70.000"
			),
			"Cayenne Schwarz" => array(	//Modell
				"Farbe" => "Schwarz",
				"Preis" => "80.000"
			)
		)
);

Ich wollte array_multisort() verwenden, aber in dem Beispiel...

array_multisort($ar[0], SORT_ASC, SORT_STRING,
                $ar[1], SORT_NUMERIC, SORT_DESC);

...wird auf das jeweilige Array mit einer Zahl zugegriffen. Die Schlüssel in dem Beispiel Array sind aber "Namen". Geht man davon aus, dass das Array noch viel größer wird und verschiedene Namen enthält, wüsste ich jetzt nicht wie man mit array_multisort() darauf zugreifen kann.

Kann mir jemand auf die Sprünge helfen?

Gruß ebody

  1. Hello,

    dein Array ist nicht sauber nach Daten und Schlüsseln getrennt. Du benutzt Daten als Schlüssel. Das ist nicht gut™.

    Wenn Du genau hinsiehst, könntest Du ein zweidimensionales (Spalten-)Array daraus machen, dass eindeutige Spaltennamen mit den dazugehörigen Werten hat, die dann pro Datensatz einen gemeinsamen Index haben.

    Dann könntest Du die PHPeigenen Sortierfuntktionen für Arrays benutzen udn müsstest nicht immer komplizierte Callback-Funktionen aufbauen.

    Siehe hierzu den Artikel im Wiki "Arrays mal anders herum"

    Die benötigten Datansatzfunktionen, die dort stehen, kann man ohne jede Änderung übernehmen, wenn man das Array "richtig herum" aufgebaut hat.

    Liebe Grüße
    Tom S.

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

    ich hoffe "Assoziatives, mehrdimensionales Array" ist für dieses Array die richtige Bezeichnung?

    Meiner Meinung nach nicht. Ich sehe da nichts dimensionales, nur verschachtelte Datensatz-Arrays. array_multisort() ist dafür nicht wirklich ausgelegt. Es erwartet eine andere Struktur. Generell meide ich array_multisort, weil mir meine Strukturierung nach Datensätzen lieber ist, als die Spalten zusammen in Arrays zu bringen.

    Um zu verstehen, wie man ein solches Array sortieren kann, verwende ich ein kleines, grobes Beispiel Array. Es soll nach der Marke (alphabetisch aufsteigend) sortiert werden und die Schlüssel der Marke, also die Modelle sollen ebenfalls (alphabetisch aufsteigend) sortiert werden.

    In deinem Fall musst du da erstmal nach der Marke sortieren. Das geht recht einfach mit einer PHP-Sortierfunktionen, die ein Array nach Schlüsseln sortiert.

    Der zweite Schritt ist, durch alle Marken zu gehen und nun die Inhalte jeweils einzeln zu sortieren. Da du auch hier wieder Daten als Schlüssel verwendest, reicht auch da wieder die Sortierung nach Schlüsseln.

    Daten als Schlüssel: Das ist in PHP noch recht einfach möglich, weil es da assoziative Arrays gibt. Die gibt es aber nicht überall. Man kann zwar gelegentlich auf Objekte ausweichen (Javascript), aber dann verliert man üblicherweise alle Array-Funktionen, oder muss sie auf umständliche Weise verwenden. Wenn man hingegen Arrays mit numerischen Keys hat und alle Daten nur in den Values stehen, nimmt man für das Sortieren eine Funktion, der man eine benutzerdefinierte Vergleichsfunktion übergeben kann.

    dedlfix.

  3. Hi,

    damit habe ich die gewünschte Ausgabe erhalten:

    ksort($autos);
    
    foreach ($autos as $autosKey => $autosValue){
    	
    	ksort($autos[$autosKey]);
    	
    }
    var_dump($autos);
    

    Gruß ebody

    1. Hello,

      damit habe ich die gewünschte Ausgabe erhalten:

      ksort($autos);
      
      foreach ($autos as $autosKey => $autosValue){
      	
      	ksort($autos[$autosKey]);
      	
      }
      var_dump($autos);
      

      Glück gehabt ;-P

      Dann schau Dir aber nochmal die Sort-Flags an, damit Du nachher nicht eine "denkwürdige" Ordnung erhältst. Groß-/Kleinschreibung und Zahlen als Werte könnten nämlich dazu führen.

      Ich habe eben erst gestutzt. Aber dein Datenmodell benötigt auch spezielle Funktionen für die Eintragung weiterer Datensätze.

      Wenn Du nun z. B. einen weiteren Porsche eintragen möchtest, musst Du auch erst schauen, ob es schon einen gibt, um nicht die vorhanden Porsche-Datensätze zu zerstören.

      Liebe Grüße
      Tom S.

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

    array_multisort bekommt 1-N Arrays. Jedes Array wird als eine Spalte einer Matrix betrachtet. Und diese Matrix wird nach Zeilen sortiert. Du kannst Dir das so vorstellen, dass in jedem Array das i-te Element als Element der Matrixzeile Nr. i betrachtet wird, und dann bei der Entscheidung, ob zwei Zeilen vertauscht werden müssen, deren Elemente vom ersten bis zum letzten verglichen werden.

    Das i-te Element ist aber nicht das Element mit dem Index i. Schön wär's. Das ist nur dann der Fall, wenn Du die Arrays mit numerischem Index in Indexreihenfolge erzeugst. Ich habe das in der PHP Sandbox ausprobiert:

    $a = ARRAY( 2=>"Rolf", 0=>"Golf", 3=>"Wolf", 1=>"Wolf");
    $b = ARRAY( 3=>47    , 1=>111     ,     2=>38, 0=>37]);
    
    array_multisort($a, $b);
    

    Rate mal, was da rauskommt. Ohne es auszuprobieren...

    Tatsächlich hat PHP eine interne Array-Ordnung, die mit den Indexen nichts zu tun hat. Die Elemente sind - solange Du nicht umsortierst - in Zugangsreihenfolge. Und die Elementnummer in DIESER Reihenfolge ist das i, das array_multisort für die Zeilenzuordnung zu Grunde legt.

    Für deine Datenstruktur also gruselig ungeeignet.

    Dass Du die Autos vielleicht besser flach speichern solltest, hatten wir schonmal gesagt. Das Sortieren wäre dann einfacher. Um ein Array aus Matrixzeilen zu sortieren, bietet PHP Sortierfunktionen mit Callback an, die dann zwei Autos vergleichen können.

    Ich habe ein bisschen gespielt. Denn für diesen Zweck bieten sich eigentlich Objekte an.

    // Ein simples Auto-Objekt mit Konstruktor, String-Aufbereitung und Sortierer
    class Auto {
        public $Marke, $Modell, $Farbe, $Preis;
        public function __construct($marke, $modell, $farbe, $preis) {
            $this->Marke  = $marke;
            $this->Modell = $modell;
            $this->Farbe  = $farbe;
            $this->Preis  = $preis;
        }
        public function __toString() {
            return "$this->Marke $this->Modell $this->Farbe $this->Preis";
        }
        // Liefert den Vergleichswert für aufsteigende Sortierung nach Marke, Modell, Farbe
        public static function compare($a1, $a2) {
            return $a1->Marke <=> $a2->Marke
                ?: $a1->Modell <=> $a2->Modell
                ?: $a1->Farbe <=> $a2->Farbe;
        }
    }
    
    // Test: 5 Autos erzeugen
    $a = [
       new Auto("Mercedes", "200", "rot", 100001),
       new Auto("Mercedes", "200", "grau", 100002),
       new Auto("Mercedes", "Vaio", "weiß", 100003),
       new Auto("Dacia", "Foo", "gelb", 10001),
       new Auto("Dacia", "Bar", "gelb", 10002),
       new Auto("Dacia", "Conan", "gelb", 10003)
    ];
    
    // Sortieren mit der compare-Methode als Sorter
    uasort($a, [ "Auto", "compare"]);
    
    foreach ($a as $u=>$v) 
       echo "$u: $v\n";
    

    Die Compare-Methode der Auto-Klasse enthält einen Leckerbissen, den ich bei Stackoverflow gefunden habe. Wenn man nach mehreren Spalten sortieren will, muss man ja solange Spalten vergleichen bis man eine findet, wo die Objekte verschieden sind. Dabei hilft zuerst mal der "Spaceship" Operator <=>, der -1, 0 oder +1 liefert, je nachdem, ob der linke Operand kleiner, gleich oder größer als der rechte ist. Und dann gibt es ?:, was eine Verkürzung des If/Then/Else Operators ist. Normalerweise hat man bedingung ? wert_für_true : wert_für_false. Die „Bedingung“ muss ohnehin nichts boolesches sein, da ist PHP ähnlich drauf wie JavaScript. Um wahr zu sein, muss sie nur wahr-artig (true-ish) sein; was true-ish ist, steht im PHP Handbuch. Und das Konstrukt $a ?: $b prüft, ob der Inhalt von $a true-ish ist, und hat dann den Wert $a. Andernfalls den Wert $b. D.h. eine Kette $a ?: $b ?: $c, in der $a, $b und $c jeweils die Werte -1, 0 oder 1 annehmen können, liefert den ersten Wert der nicht 0 ist.[1]

    Rolf

    --
    sumpsi - posui - clusi

    1. PHP ist hier etwas anders als JavaScript. Dort hätte man einfach das logische OR (||) nehmen können, weil in JavaScript (a || b === a) gilt wenn a truthy ist). In PHP erzeugt || immer TRUE oder FALSE. ↩︎

  5. Hallo,

    nachdem hier jetzt schon drei Experten erklährt haben, wie es geht, brauche ich mal Nachhilfe:

    Was bringt es, ein assoziatives Array zu sortieren. In assoziativen Arrays gibt es doch keine Reihenfolge?

    Gruß
    Jürgen

    1. Tach!

      Was bringt es, ein assoziatives Array zu sortieren. In assoziativen Arrays gibt es doch keine Reihenfolge?

      Das kann man so nicht verallgemeinern. Es gibt einige Systeme, die sortieren sich die Schlüssel, wie sie es brauchen. Aber PHP macht das nicht, das behält die Reihenfolge. Man kann deshalb mit foreach drüberlaufen, und verarbeitet die Einträge in der selbst erstellten Reihenfolge.

      dedlfix.

      1. Hallo deflfix,

        Danke.

        Gruß
        Jürgen

    2. Hallo,

      Was bringt es, ein assoziatives Array zu sortieren.

      Gar nichts.

      In assoziativen Arrays gibt es doch keine Reihenfolge?

      Und selbst wenn: Sie spielt keine Rolle.

      MfG

      1. Tach!

        Was bringt es, ein assoziatives Array zu sortieren.

        Gar nichts.

        Anderenorts vielleicht, PHP behält aber die Reihenfolge bei und ändert sie nur aufgrund von konkreten Handlungen des Verwenders.

        In assoziativen Arrays gibt es doch keine Reihenfolge?

        Und selbst wenn: Sie spielt keine Rolle.

        In anderen Anwendungsfällen vielleicht. Da PHP aber die Reihenfolge garantiert, kann man ihr hier sehr wohl eine Rolle zuordnen.

        dedlfix.

        1. Der Sinn assoziativer Arrays ist nicht die Reihenfolge der Einträge sondern die direkte Adressierbarkeit der Werte über die Schlüssel. MfG

          1. Tach!

            Der Sinn assoziativer Arrays ist nicht die Reihenfolge der Einträge sondern die direkte Adressierbarkeit der Werte über die Schlüssel.

            Ja, normalerweise schon. Aber wenn PHP hier eine garantierte Funktionalität bietet, warum soll man ihr nicht auch einen Sinn zuweisen und in einem entsprechenden Anwendungsfall nutzen?

            dedlfix.

            1. Tach!

              Der Sinn assoziativer Arrays ist nicht die Reihenfolge der Einträge sondern die direkte Adressierbarkeit der Werte über die Schlüssel.

              Ja, normalerweise schon. Aber wenn PHP hier eine garantierte Funktionalität bietet, warum soll man ihr nicht auch einen Sinn zuweisen und in einem entsprechenden Anwendungsfall nutzen?

              Ja, dann beschreibe doch mal einen entsprechenden Anwendungsfall.

              MfG

              1. Tach!

                Ja, dann beschreibe doch mal einen entsprechenden Anwendungsfall.

                https://forum.selfhtml.org/self/2018/sep/22/assoziatives-mehrdimensionales-array-sortieren/1732402#m1732402

                dedlfix.

                1. Tach!

                  Ja, dann beschreibe doch mal einen entsprechenden Anwendungsfall.

                  https://forum.selfhtml.org/self/2018/sep/22/assoziatives-mehrdimensionales-array-sortieren/1732402#m1732402

                  Meine Frage war wozu das gut sein soll. Also nicht die Problemstellung sondern ein konkreter Anwendungsfall wo es sinnvoll ist, ein assoziatives Array zu sortieren!

                  MfG

                  1. Tach!

                    Meine Frage war wozu das gut sein soll. Also nicht die Problemstellung sondern ein konkreter Anwendungsfall wo es sinnvoll ist, ein assoziatives Array zu sortieren!

                    Verstehe nicht, worauf du hinauswillst. Die Problemstellung des OP ist ein konkreter Anwendungsfall. Es geht hier um Arrays in PHP, nicht um Arrays anderswo oder eine theoretische Beschreibung von Arrays.

                    Der OP hat einen Anwendungsfall, den er mit dem löst, was PHP als Array bezeichnet. (Ob er das gut oder schlecht tut, sei dahingestellt.) Jedenfalls lässt sich das mit dieser Struktur lösen. Dass die anderenorts andere benannt werden (z.B. SortedMap), ist für PHP nicht weiter relevant.

                    dedlfix.

          2. Hello,

            Der Sinn assoziativer Arrays ist nicht die Reihenfolge der Einträge sondern die direkte Adressierbarkeit der Werte über die Schlüssel. MfG

            Das kommt immer auf die tatsächliche Bauweise an, was möglich ist und, wie Dedlfix schon hinwies, was von der jeweiligen Programmiersprache garantiert wird.

            "Array" bedeutet in Pascal etwas anderes, als in PHP.

            |Die Benutzung der Bezeichnung "Array" in PHP für diese mächtigen Strukturen finde ich vollkommen daneben!|

            Liebe Grüße
            Tom S.

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

              |Die Benutzung der Bezeichnung "Array" in PHP für diese mächtigen Strukturen finde ich vollkommen daneben!|

              Entscheidend ist der Begriff assoziativ. Was ja auch den Sinn solcher Strukturen ausdrückt.

              MfG

      2. Hello,

        Was bringt es, ein assoziatives Array zu sortieren.

        Gar nichts.

        Verstehe ich nicht. Warum sollte man das nicht nach einer Eigenschaft (Schlüssel, Wert, Datentyp) seiner Elemente sortieren können?

        In assoziativen Arrays gibt es doch keine Reihenfolge?

        Doch, die gibt es bei PHP. Die Reihenfolge in der Kette der Elemente bleibt erhalten. Man kann vorne oder hinten Elemente anhängen oder gezielt welche dazwischen bauen.

        Und selbst wenn: Sie spielt keine Rolle.

        Das kommt doch immer auf den Anwendungsfall an.
        Wenn man seine verkettete Liste nach dem Wert alphanumerisch caseunsensitive sortieren will, ist das durchaus möglich. Wenn die assoziativen Keys erhalten bleiben sollen, so wie in meinem Wiki-Artikel, benutzt man asort().

        Anschließend kann man es beliebig oft in diesen Sortierungen mit foreach() ausgeben lassen/weiterverarbeiten.

        Liebe Grüße
        Tom S.

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

          Anschließend kann man es beliebig oft in diesen Sortierungen mit foreach() ausgeben lassen/weiterverarbeiten.

          Na endlich kommen wir zur Sache: Nämlich zur Ausgabe! Denn da macht ja eine Sortierung erst einen Sinn. D.h. auch daß es genügt, die Sortierung während der Ausgabe vorzunehmen. Darüber hinaus kann eine bestimmte Reihenfolge der Felder vom Template vorgegeben werden sein, das ist bei der Ausgabe von Tabellen so üblich:

          Name|Vorname|PLZ|Ort %name%|%vname%|%plz%|%ort%

          wobei die Reihenfolge der Platzhalter im Array selbst völlig unbedeutend ist und erst das Template über die Reihenfolge entscheidet.

          MfG

          1. Tach!

            Anschließend kann man es beliebig oft in diesen Sortierungen mit foreach() ausgeben lassen/weiterverarbeiten.

            Na endlich kommen wir zur Sache: Nämlich zur Ausgabe! Denn da macht ja eine Sortierung erst einen Sinn.

            Meinst du, dass der OP seine Daten nur so zum Spaß sortieren möchte? Und warum sollte eine Sortierung ohne Ausgabe nicht auch sinnvoll sein?

            D.h. auch daß es genügt, die Sortierung während der Ausgabe vorzunehmen.

            Selbst wenn, warum sollte man dazu nicht die vorhandene Struktur sortieren können?

            Darüber hinaus kann eine bestimmte Reihenfolge der Felder vom Template vorgegeben werden sein, das ist bei der Ausgabe von Tabellen so üblich:

            Das ist ein ganz anderes Thema.

            dedlfix.

            1. Tach!

              Anschließend kann man es beliebig oft in diesen Sortierungen mit foreach() ausgeben lassen/weiterverarbeiten.

              Na endlich kommen wir zur Sache: Nämlich zur Ausgabe! Denn da macht ja eine Sortierung erst einen Sinn.

              Meinst du, dass der OP seine Daten nur so zum Spaß sortieren möchte? Und warum sollte eine Sortierung ohne Ausgabe nicht auch sinnvoll sein?

              Genau diese Frage ist immer noch offen.

              MfG

    3. Hello Jürgen,

      #Modellvorstellung: es gibt eine Verkettung von Elementen. Deren Reihenfolge bleibt erhalten. Erweiterungen können am Ende "automatisch" oder mit array_push oder am Anfang mit array_unshift vorgenommen werden

      Die Elemente tragen Eigenschaften:

      • Vorgänger (1)
      • Nachfolger (2)
      • Schlüssel
      • Wert
      • Datentyp (Elementtyp: Knoten/Blatttypen)

      Wenn Datentyp == Knoten ist, zeigt Wert auf eine weitere Liste.

      Damit wird dann aus der einfachen Liste (Kette) eine Liste von Listen (Baum, auch unvollständige oder unregelmäßige Baumstruktur).

      Selbstverständlich kann man Ketten und Bäume sortieren nach jeweils einer der Eigenschaften ihrer Elemente.

      Wie PHP das wirklich baut (Hashlists) interessiert hier nicht. PHP sorgt dafür, dass innerhalb einer Kette (Liste) kein Schlüssel doppelt vorkommen kann. Und PHP sorgt sich um die Allokation/Rückgabe und die Größe des benötigten Speicherplatzes für den Wert ("Payload"). Darum muss sich der Programmierer also nicht kümmern.

      #BTW: Und wer mir auf meinen Beitrag ein (-1) gegeben hat, hat Arrays (eigentlich Baumstrukturen) in PHP noch nicht verstanden und was man damit alles anstellen kann ;-)

      Allerdings muss ich gestehen, dass der Wiki-Artikel ohne Bilder auch nur schwer zu verstehen ist. Die wollte ich immer nochmal nachliefern zusammen mit den nicht ausgefüllten Absätzen.

      Das gab es wohl schon mal im Archiv. Ist aber leider nicht mehr erreichbar.

      Ein paar Fragmente sind noch da:

      ##Einfaches Array:
      Einfache Liste

      ##Mehrfachverkettung:
      Baumstruktur

      Liebe Grüße
      Tom S.

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

        eigentlich bin ich PL‘s Meinung. Echte Arrays, also mit Indexzugriff, haben eine Reihenfolge und können daher sortiert werden. Assoziative Arras sind für mich Strukturen mit benannten Elementen. Eine Reihenfolge gibt es allenfalls im Speicher. Wenn aber PHP da die Möglichkeit bietet, diese Reihenfolge zu nutzen, warum nicht.

        Gruß
        Jürgen

        1. Hello,

          eigentlich bin ich PL‘s Meinung. Echte Arrays, also mit Indexzugriff, haben eine Reihenfolge und können daher sortiert werden. Assoziative Arras sind für mich Strukturen mit benannten Elementen. Eine Reihenfolge gibt es allenfalls im Speicher. Wenn aber PHP da die Möglichkeit bietet, diese Reihenfolge zu nutzen, warum nicht.

          Darum vertrete ich ja auch schon, seitdem ich hier poste (Tom) die Meinung, dass die Bezeichnung "Array" in PHP für diese mächtigen Strukturen total falsch ist.

          Liebe Grüße
          Tom S.

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

          Echte Arrays, also mit Indexzugriff, haben eine Reihenfolge und können daher sortiert werden. Assoziative Arras sind für mich Strukturen mit benannten Elementen.

          PHPs Array-Struktur ist anders als nur ein einfaches Array anderenorts.

          „An array in PHP is actually an ordered map. A map is a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. As array values can be other arrays, trees and multidimensional arrays are also possible.“

          Wie der Handbuchtext sagt, kann man es für eine ganze Reihe weiterer Aufgaben nutzen, für die man in anderen Systemen spezialisierte Strukturen verwendet.

          dedlfix.

      2. Und wer mir auf meinen Beitrag ein (-1) gegeben hat, hat Arrays (eigentlich Baumstrukturen) in PHP noch nicht verstanden und was man damit alles anstellen kann ;-)

        Die Bewertung kommt von mir, weil es mit Spaltenarrays technische Schwierigkeiten gibt, das habe ich an anderer Stelle auch mal erklärt.

        1. Hello,

          Die Bewertung kommt von mir, weil es mit Spaltenarrays technische Schwierigkeiten gibt, das habe ich an anderer Stelle auch mal erklärt.

          Ich find's immer gut, wenn man weiß, was bemängelt wurde ;-)

          Alle einfachen PHP-eigenen Aggregats- und Sortierfunktionen werden durch "Zeilenarrays" unbenutzbar.

          Um auf das Beispiel "Preis + Versandkosten" zurückzukommen, benötigt man dafür am einfachsten eine eigene Spalte. Die kann man aber leicht erzeugen. Und dann kann man die wieder mit asort() sortieren.

          $_data['gesamtpreis'] = array();
          
          foreach ($_data['preis'] as $key -> $preis)
          {   
              $_data['gesamtpreis'][$key] = $preis + $_data['versand'][$key];
          }
          
          asort($_data['gesamtpreis'], SORT_NUMERIC); 
          

          Man kann nun auch den maximalen Preis, den niedrigsten Preis, die Summe einer Spalte, den mittleren Preis (=summe/anzahl), usw. ganz leicht mit den Standard-Arrayfunktionen von PHP bestimmen.

          Das schöne an der "Spaltenarray"-Variante ist außerdem, dass die Sortierungen nach einer Spalte erhalten bleiben solange das Array lebt. Man muss dann nur noch die passende Spalte auswählen und mit foreach() nach ihren Keys get_record() aufrufen.

          Bei der Anwendung muss man eben immer nur darauf achten, dass man nicht aus Versehen mal sort() benutzt. Dann sind die Datensätze kaputt.

          Liebe Grüße
          Tom S.

          --
          Es gibt nichts Gutes, außer man tut es!
          Das Leben selbst ist der Sinn.
          1. Die Bewertung kommt von mir, weil es mit Spaltenarrays technische Schwierigkeiten gibt, das habe ich an anderer Stelle auch mal erklärt.

            Ich find's immer gut, wenn man weiß, was bemängelt wurde ;-)

            Das kann ich sehr gut verstehen, und auch den Reflex sich verteidigen zu müssen. Allerdings löst so eine reflexartige Reaktion, nur selten die Bereitschaft deines Gegenüber aus, sich nochmal zu erklären. Mit einer höfliche Bitte um Feedback hast du mehr Aussichten auf Erfolg und das liegt ja in deinem Interesse.

            Alle einfachen PHP-eigenen Aggregats- und Sortierfunktionen werden durch "Zeilenarrays" unbenutzbar.

            Um auf das Beispiel "Preis + Versandkosten" zurückzukommen, benötigt man dafür am einfachsten eine eigene Spalte. Die kann man aber leicht erzeugen. Und dann kann man die wieder mit asort() sortieren.

            Den Gedanken habe ich in der früheren Diskussion ja auch bereits geäußert, aber das finde ich keine gute Lösung. Dieser Ansatz mischt Stammdaten, die für die Geschäftslogik relevant sind, mit administrativen Daten, die für die Ausführung spezifischer Algorithmen gebraucht werden. Das ist unhygiensch. Man muss darauf achten, dass die temporäre Spalte konsistent mit den Stammdaten ist, ändert sich der Preis, muss auch der Gesamtpreis aktualisiert werden. Außerdem muss man darauf achten, dass es keine Namenskollision zwischen den Spalten gibt. Das lässt sich alles irgendwie lösen, aber das bedeutet Aufwand, und ich sehe ehrlich gesagt noch keinen Vorteil.

            PHP hat eine eingebaute generische Sortierfunktion, der man belibeige Sortierkriterien übergeben kann. Für eine neue spezifische Sortierfunktion reicht es dann, nur noch das Kriterium zu definieren - das reduziert den Programmieraufwand auf die Essenz des Problems.

            Zumal die Datenstruktur hier sowieso schon als Zeilenarray vorlag. Man müsste sie also erstmal in die Form eines Spaltenarrays bringen. Genauso, werden Datenbank-Ergebnismengen zeilenweise gelesen, solche Daten müsste man auch erst transponieren. Und man muss bei Spaltenarrays viele typische Container-Operationen neu implementieren, für die primitven CRUD-Operatinen, hast du das freundlicherweise schon gemacht und die Leistung will auch auch gar nicht schmälern, dennoch muss das für komplexere Operationen, wie array_map, array_reduce oder array_filter noch gemacht werden, wenn sie denn gebraucht werden. Dann ensteht auch wieder Mehraufwand.

            Für kleine Beispiele ist das folgende vielleicht weniger relevant, aber man sollte zumindest im Hinterkopf haben, dass Operationen auf Spaltenarrays – jedenfalls die aus dem Wiki-Artikel – schlechteres komplexsitätstheoretisches Laufzeitverhalten haben. Wenn n die Anzahl der Datensätze ist, und m die Anzahl der Felder in einem Datensatz, dann hat ein direkter Lesezugriff die Komplexitätsklasse O(1) in einem Zeilenarray, in einem Spaltenarray aber O(m). Das Transponieren, das vorher nötig ist, hat sogar O(n*m), das ist der Faktor der ensteht, wenn man eine MySQL-Ergebnismenge in ein Spaltenarray umwandeln muss.

            Außerdem, funktioneren Zeilen-Arrays auch mit klassischen objekt-orientierten Entwürfen. Ich kann ein Array von Objekten mit genau den selben Operationen traversieren und manipulieren, wie ein Array von Arrays oder ein Array von Integern. Man kann also mehr Funktionen wieder verwenden.

            1. Hallo 1unitedpower,

              ich bin durchaus für Zeilenarrays und finde Spaltenarrays ebenfalls nur für spezielle Anwendungsfälle geeignet, aber hier hast Du Dich vergallopiert, meine ich:

              Wenn n die Anzahl der Datensätze ist, und m die Anzahl der Felder in einem Datensatz, dann hat ein direkter Lesezugriff die Komplexitätsklasse O(1) in einem Zeilenarray, in einem Spaltenarray aber O(m)

              In einem Array aus Zeilenarrays habe ich beim Zugriff auf t Werte einer Zeile einen Arrayzugriff um das Zeilenarray aus dem Haupt-Array zu holen, und dann t Array-Zugriffe für die Felder. Insgesamt t+1 Arrayzugriffe, das ist O(t). Wenn ich n Zeilen verarbeite, habe ich n Zugriffe für die Zeilenarrays und n*t Zugriffe für die Werte, also n(t+1) Arrayzugriffe. Das ist O(nt). Auch, wenn ich das Hauptarray mit foreach verarbeite, ist jeder foreach-Schritt ein Zeilenzugriff. Zwar schneller, aber trotzdem ein Zugriff. Es bleibt O(nt).

              In Array aus Spaltenarrays habe ich je Feld einen Zugriff auf den Spaltenkopf und einen für den Zeileneintrag, also 2t, aber trotzdem O(t). Wenn ich n Zeilen verarbeite und die Spaltenköpfe cache, habe ich t Zugriffe für's cachen und n*t Zugriffe für die Werte, also (n+1)t Arrayzugriffe. Ohne Cache hätte ich 2nt Arrayzugriffe. Das ist aber immer noch O(nt).

              D.h. für eine einzelne Zeile bin ich in beiden Fällen O(t) und für n Zeilen in beiden Fällen O(nt). In der Komplexitätsklasse ergibt sich kein Unterschied.

              In der realen Laufzeit dürfte es sich aber schon unterscheiden. Wenn ich die Zeilen per Key abrufen muss und kein foreach verwenden kann, hat das Spaltenarray mit gecachten Spaltenköpfen ggf. einen kleinen Vorteil. Wenn es darum geht, auf einer einzigen Spalte zu aggregieren oder zu sortieren, dürfte das Spaltenarray ebenfalls von Vorteil sein. Nicht in der Größenordnung, aber in absoluter Laufzeit.

              Unter dem Strich glaube ich aber trotzdem an die Vorteile des Zeilenarrays. Wenn ich eine Zeile an eine Funktion als Parameter übergeben will, ist das bei Zeilenarrays deutlich einfacher. Wenn ich eine neue Zeile aus einer Funktion zurückbekomme (z.B. $mysqli->fetch_assoc()), ist sie an ein Zeilenarray deutlich leichter anzuhängen.

              Rolf

              --
              sumpsi - posui - clusi
              1. In einem Array aus Zeilenarrays habe ich beim Zugriff auf t Werte einer Zeile einen Arrayzugriff um das Zeilenarray aus dem Haupt-Array zu holen, und dann t Array-Zugriffe für die Felder.

                Du gehst von einer anderen Operation aus als ich. Bzw. du hast mehrere primitive Operationen miteinander verknüpft und eine zusammengesetze Operation analysiert. Ich sprach nur vom Zugriff über einen Index auf einen Datensatz einer Datensatzsammlung. Wenn die Datensatzsammlung ein Zeilenarray ist, braucht dieser Zugriff konstante Laufzeit. Wenn die Sammlung ein Spaltenarray ist, dann braucht dieser Zugriff O(m), ein Array-Zugriff je Spalte (~Feld), das ist die asymptotische Laufzeit von get_record.

                Du hast jetzt aber noch mehr gemacht, du hast dieser Operation noch t Lesezugriffe auf Felder eines Datensatzes nachgelagert. Im Falle des Zeilenarrays haben wir dann O(1) + O(t). Im Falle des Spaltenarrays haben wir dagegen: O(m) + O(t). Das ist die Lazfzeit, der zusammengesetzten Operation, die du gemeint hast, aber unter Einbeziehung der Anzahl der Felder m des Datensatzes.

            2. Hello,

              Den Gedanken habe ich in der früheren Diskussion ja auch bereits geäußert, aber das finde ich keine gute Lösung. Dieser Ansatz mischt Stammdaten, die für die Geschäftslogik relevant sind, mit administrativen Daten

              Das muss man nicht. Ich habe es eben in dem Beispiel nur so gemacht.

              $_sorted['gesamtpreis'] = array();
              
              foreach ($_data['preis'] as $key -> $preis)
              {   
                  $_sorted['gesamtpreis'][$key] = $preis + $_data['versand'][$key];
              }
              
              asort($_sorted['gesamtpreis'], SORT_NUMERIC);
              

              Nun sind die Daten aus der Datenhaltung und die für den Sortiervorgang in getrennten Arrays untergebracht. Dadurch stören sie in den Funktionen für die Datensatzmanipulation bzw. das get_record() nicht mehr.

              [...] Man muss darauf achten, dass die temporäre Spalte konsistent mit den Stammdaten ist, ändert sich der Preis, muss auch der Gesamtpreis aktualisiert werden. Außerdem muss man darauf achten, dass es keine Namenskollision zwischen den Spalten gibt. Das lässt sich alles irgendwie lösen, aber das bedeutet Aufwand, und ich sehe ehrlich gesagt noch keinen Vorteil.

              Das stimmt. Beim Programmieren muss man immer auf etwas achten.
              Man könnte, wenn es objektorientiert verpackt wird, selbstverständlich die Methoden auch kapseln und gegeneinander absichern. Dann hat man nur noch eine Blackbox, die selber an alles denkt.

              Ich will das hier aber nicht weiter ausdehen. Die Diskussion um Spalten- oder Zeilenarrays ist schon so alt, wie die Einführung von $_FILES in PHP.

              Man kann es so oder so machen und man wird immer Argumente gegen die eine oder die andere Methode finden, wenn man das will. Man kann aber auch sagen: "prima, es gibt unterschiedliche Vorgensweisen für die Datenorganisation und die haben jeweils ihre ganz eigenen Vorteile".

              Liebe Grüße
              Tom S.

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

                Ich will das hier aber nicht weiter ausdehen. Die Diskussion um Spalten- oder Zeilenarrays ist schon so alt, wie die Einführung von $_FILES in PHP.

                Ach jetzt weiß ich erstmal was Du die ganze Zeit mit Zeilen//Spaltenarray meinst. Natürlich ist $_FILES mächtig gewaltig und zwar mächtig grottig.

                Array
                (
                    [upspot] => Array
                        (
                            [name] => Array
                                (
                                    [0] => ehmetsklinge.jpg
                                    [1] => eichelberg.jpg
                                )
                
                            [type] => Array
                                (
                                    [0] => image/jpeg
                                    [1] => image/jpeg
                                )
                
                            [tmp_name] => Array
                                (
                                    [0] => C:\WINDOWS\Temp\phpB.tmp
                                    [1] => C:\WINDOWS\Temp\phpC.tmp
                                )
                
                            [error] => Array
                                (
                                    [0] => 0
                                    [1] => 0
                                )
                
                            [size] => Array
                                (
                                    [0] => 11761
                                    [1] => 17479
                                )
                
                        )
                
                )
                

                um da mal ein Beispiel zu zeigen wie man es nicht machen sollte. Besser ist eine Struktur wie folgt:

                'upspot' => [
                                                            bless( {
                                                                     'content_length' => '17479',
                                                                     'content_type' => 'image/jpeg',
                                                                     'filename' => 'eichelberg.jpg',
                                                                     'iohandle' => bless( \*Symbol::GEN3, 'IO::String' ),
                                                                     'mtime' => '1386763302',
                                                                     'mtime_gm' => 'Wed Dec 11 12:01:42 2013',
                                                                     'mtime_local' => 'Wed Dec 11 13:01:42 2013',
                                                                     'name' => 'upspot'
                                                                   }, 'xCGI::File' )
                                                          ]
                                            },
                

                die man natürlich auch in PHP haben könnte. Der Unterschied dürfte klar erkennbar sein: Nur eine Referenz auf zusammengehörige Daten.

                Man kann aber auch sagen: "prima, es gibt unterschiedliche Vorgensweisen für die Datenorganisation und die haben jeweils ihre ganz eigenen Vorteile".

                Für was man sich entscheidet ist eine Frage der Zweckmäßigkeit. Und eine Frage des wahlfreien Zugriffes. Zweifelsfrei jedoch gehören die Eigenschaften zum Objekt eichelberg.jpg zusammen und nicht sonstwohin in einem Array verteilt.

                MfG

  6. Hallo,

    ich hoffe "Assoziatives, mehrdimensionales Array" ist für dieses Array die richtige Bezeichnung?

    Nein. Es sind Arrays in Arrays. Und genauso wird das auch sortiert: Jedes Array für sich.

    MfG

    1. Hello,

      ich hoffe "Assoziatives, mehrdimensionales Array" ist für dieses Array die richtige Bezeichnung?

      Nein. Es sind Arrays in Arrays. Und genauso wird das auch sortiert: Jedes Array für sich.

      Nein. Es sind (als Modellvorstellung) verkettete Listen in verketteten Listen.

      Und PHP-intern sind es Hashtables, also Listen, die auf Elemente mit Eigenschaften verweisen mit redundant konsolidierten Werten als Hashes. Das macht sie bei passender Verwendung extrem schnell.

      Liebe Grüße
      Tom S.

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

        ich hoffe "Assoziatives, mehrdimensionales Array" ist für dieses Array die richtige Bezeichnung?

        Nein. Es sind Arrays in Arrays. Und genauso wird das auch sortiert: Jedes Array für sich.

        Nein. Es sind (als Modellvorstellung) verkettete Listen in verketteten Listen.

        In verketteten Listen gibt es Zeiger die auf den Vorgänger/Nachfolger zeigen. Siehst Du die irgendwo in dem Array was hier vorstellig wurde?

        Also ich sehe da nichts dergleichen.

        MfG

        1. Hello,

          ich hoffe "Assoziatives, mehrdimensionales Array" ist für dieses Array die richtige Bezeichnung?

          Nein. Es sind Arrays in Arrays. Und genauso wird das auch sortiert: Jedes Array für sich.

          Nein. Es sind (als Modellvorstellung) verkettete Listen in verketteten Listen.

          In verketteten Listen gibt es Zeiger die auf den Vorgänger/Nachfolger zeigen. Siehst Du die irgendwo in dem Array was hier vorstellig wurde?

          Also ich sehe da nichts dergleichen.

          Du kannst einige Zeiger in PHP zwar implizit ermitteln und verwenden, aber PHP lässt dich glücklicherweise nicht heran, sondern kapselt diese.
          [das "dich" habe ich in vollem Bewusstsein klein geschrieben, es meint also nicht Dich]

          und einige andere, die auch den Zeiger manipulieren.

          |Wichtig ist dabei, dass jeder Zweig des Baumes (sollte es einer sein), einen eigenen Zeiger verwaltet.|

          Liebe Grüße
          Tom S.

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

            ich hoffe "Assoziatives, mehrdimensionales Array" ist für dieses Array die richtige Bezeichnung?

            Nein. Es sind Arrays in Arrays. Und genauso wird das auch sortiert: Jedes Array für sich.

            Nein. Es sind (als Modellvorstellung) verkettete Listen in verketteten Listen.

            In verketteten Listen gibt es Zeiger die auf den Vorgänger/Nachfolger zeigen. Siehst Du die irgendwo in dem Array was hier vorstellig wurde?

            Also ich sehe da nichts dergleichen.

            Du kannst einige Zeiger in PHP zwar implizit ermitteln und verwenden, aber PHP lässt dich glücklicherweise nicht heran, sondern kapselt diese.

            Stimmt. Das ist in Perl ganz genauso. MfG