Michael: bestimmtes array ausgeben

Es sind immer verschiedene Werte in meinem Array, das heißt die erste Nummerierung ändert sich dauernd. Der Wert mit der ID 1 ist immer gleich.

   [0] => Array
        (
            [id] => 1
            [inhalt] => Titel mit Inhalt
            [daten] => 1
        )

    [1] => Array
        (
            [id] => 6
            [inhalt] => Titel ohne inhalt
            [daten] => 3
        )

Im Augenblick mache ich es so

$i = 0;
while($i < count($ausgabe))
	{
	if($ausgabe[$i]['id']==1)
		{
		echo'<h1>'.$ausgabe[$i]['inhalt'].'</h1>';
		}
	$i++;
	}

Aber ich glaube ich mache das zu kompliziert

  1. Aber ich glaube ich mache das zu kompliziert

    Ja. Und zwar von Anfang an. Du baust den Array ja irgendwo zusammen. Ich nehme mal an, Dein $i sei eindeutig.

    Statt also:

    schleife {
        # irgendwas
        $ar['id']=$identifier;
        $ar['inhalt']=$text;
        $ar['daten']=$daten;
        $arAr[]=$ar;
    }
    

    nimm gleich den identifier um die Daten an die richtige Position im Array zu hängen::

    schleife {
        # irgendwas
        #$identifier;
        $arAr['$identifier']['inhalt']=$text;
        $arAr['$identifier']['daten']=$daten;
    }
    

    Die Ausgabe?

    <h1><?=$ausgabe[1]['inhalt'];?></h1>';
    
    1. Hallo Regina,

      ich brech ab - offenbar habe ich eine Dreiviertelstunde an meinem Aufsatz unten geschrieben, weil ich nämlich anfing bevor hier eine andere Antwort war...

      Rolf

      --
      sumpsi - posui - clusi
    2. Kleine Korrektur:

      Falsch:

          $arAr['$identifier']['inhalt']=$text;
          $arAr['$identifier']['daten']=$daten;
      

      Richtig:

          $arAr[$identifier]['inhalt']=$text;
          $arAr[$identifier]['daten']=$daten;
      

      Gut, dass ich es nicht als PHP ausgezeichnet hatte… wegduck

  2. @@Michael

    Wenn ich dich richtig verstehe, suchst du array_search() und das in diesem Beispiel Gezeigte.

    LLAP 🖖

    --
    „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
    1. Hallo Gunnar,

      array_column erzeugt ein Temp-Array und durchläuft erstmal das ganze $ausgabe Array. Das ist zwar schnell getippt, aber nicht effizient.

      Leider werden solche Konstrukte werden von PHP-Programmierern oft genutzt, mit der Begründung, dass das Selbstschreiben einer effizienteren Suchfunktion unnötige Mikrooptimierung ist, aber auf einem belasteten Server kann sparsamer Einsatz von temporären Strukturen, sprich eine Entlastung des Garbage-Collectors - schon einen Unterschied ausmachen. Denn wer so programmiert, hat solche Konstrukte an vielen Stellen im Programm.

      Rolf

      --
      sumpsi - posui - clusi
      1. Leider werden solche Konstrukte werden von PHP-Programmierern oft genutzt, mit der Begründung, dass das Selbstschreiben einer effizienteren Suchfunktion unnötige Mikrooptimierung ist

        Schön, wenn das so wäre. Ich glaube aber, dass leider das Gegenteil der Fall ist.

        aber auf einem belasteten Server kann sparsamer Einsatz von temporären Strukturen, sprich eine Entlastung des Garbage-Collectors - schon einen Unterschied ausmachen.

        Wenn dem so ist, ist das mit einem Profiling schnell entdeckt und behoben. Wenn der Flaschenhals woanders liegt, ist das mit einem Proliging ebenfalls schnell entdeckt und behoben. Optimieren auf Verdacht ist selten erfolgreich, die Entwicklung dauert länger, die Code-Basis wächst und wird unverständlich. Deshalb lautet die goldene Regel: Optimieren wenn es zu spät ist. Optimieren ist wie Schatzsuchen: Man kann überall am Strand seine Löscher buddeln, darüber stolpern und am Ende des Tages körperlich erschöpft und ohne den Schatz nach Hause gehen. Oder man nimmt einen Metalldetektor mit und buddelt nur da wo es einen Ping gibt, das spart Energie und Zeit und es steigert die Wahrscheinlichkeit, dass man am Ende des Tages ungeschunden und mit dem Schatz nach Hause gehen kann.

        1. dass man am Ende des Tages ungeschunden und mit dem Schatz nach Hause gehen kann.

          Naja. Gerade in Hinblick auf "Suchfunktionen" ist es von Vorteil sein, sich von vorn herein über die beabsichtigten Funktionen im Klaren zu sein und die, ich nenn's mal "Datenhaltung", daran anzupassen. Das betrifft auch den Aufbau der Arrays. Vorliegend dürfte(!) der Aufwand nämlich ziemlich obsolet sein.

          Der größte Mist, den ich bisher sah, waren allerdings zweidimensionale Arrays, bei denen der Warenkorb pro Klick um eine Spalte(!) erweitert wurde…

          b.t.w.:

          Unter "Suchfunktion" verstehe ich eher sowas.

          1. dass man am Ende des Tages ungeschunden und mit dem Schatz nach Hause gehen kann.

            Naja. Gerade in Hinblick auf "Suchfunktionen" ist es von Vorteil sein, sich von vorn herein über die beabsichtigten Funktionen im Klaren zu sein und die, ich nenn's mal "Datenhaltung", daran anzupassen. Das betrifft auch den Aufbau der Arrays.

            Im Vorfeld muss nur geklärt sein, was da berechnet werden soll, nicht aber das wie. Für das wie sollte man erstmal die verständlichste Variante implementieren. Stellt sich beim Profiling heraus, dass die Suche unverhältnismäßig langsam ist, dann kann man die Implementierung immernoch anpassen.

            Vorliegend dürfte(!) der Aufwand nämlich ziemlich obsolet sein.

            Das geht in die selbe Richtung, wie die von Rolf B vorgeschlagene Lösung. Aber da ist erstmal nichts gewonnen. Du brauchst O(n) um die Hashmap zu erstellen und nochmal O(1) für den Lookup (im worst case sogar nochmal O(n)), das ist nicht effizienter als eine lineare Suche über eine Liste. Der Vorteil der Hashmap macht sich erst bemerkbar, wenn man mehrere Lookups macht, was im vorliegenden Fall nicht gegeben zu sein scheint. Von daher ist das ein gutes Beispiel für vergebene Liebesmühe. Und selbst wenn man hier von der Effizienz der Hashmap profitieren würde, könnte es immernoch sein, dass der eigentliche Flaschenhals an einer ganz anderen Stelle liegt. Falls das doch der Flaschenhals sein sollte, wird ein Profling das zu Tage fördern und dann kann man das immernoch optimieren.

            1. Das geht in die selbe Richtung, wie die von Rolf B vorgeschlagene Lösung.

              Mitnichten. Ich empfehle statt

              ar[0][1[id]=1
              ar[0][1[text]='Eine Überschrift'
              ar[0][1[daten]='...'
              
              ar[1][2[id]=2
              ar[1][2[text]='Andere Überschrift'
              ar[1][2[daten]='...'
              

              zu fummeln und dann nach der ID zu wühlen, gleich:

              ar[1][text]='Eine Überschrift'
              ar[1][daten]='...'
              
              ar[2][text]='Andere Überschrift'
              ar[2][daten]='...'
              

              zu "bauen" und nach dem Element [1] zu greifen.

              Das spart nachrechenbar Umwege.

              1. Hallo Regina,

                das war durchaus mein Prio-1 Vorschlag: Bau die Datenstruktur gleich effizient auf. Das ist zwar O(n), aber das Aufbauen des Array-Struktur aus dem Eingangsposting ist das ebenfalls. Insofern kostet die Hashmap nichts extra. Dafür gewinnt man aber bei der Suche, dass man von O(n) auf O(1) kommt.

                Andererseits sind Diskussionen wie diese hier - finde ich - durchaus interessant und für einen Einsteiger können sie auch lehrreich sein (sofern wir ihn nicht abhängen).

                Apropos lehrreich: Vielleicht ist die O-Notation nicht jedem vertraut. Dem kann ich ansatzweise abhelfen. Wo man das im Wiki verlinken kann, muss man sehen.

                Rolf

                --
                sumpsi - posui - clusi
  3. Hallo Michael,

    Aber ich glaube ich mache das zu kompliziert

    nein, nicht wirklich. Es gibt keine PHP-Funktion, die Dir die benötigte Funktionalität fertig liefert. array_filter wäre eine Möglichkeit, aber das ist für den Anwendungsfall viel zu ineffizient (es durchläuft das ganze Array und produziert ein neues Array).

    Deinen Code würde ich in folgenden Punkten als verbesserungsfähig ansehen:

    • man trennt nach Möglichkeit Logik und Ausgabe. Dann kann man die Logik wiederverwenden
    • es gibt bessere Möglichkeiten, ein Array zu durchlaufen
    • Suchschleifen bricht man beim Treffer ab

    Aber: Bevor man Code optimiert, prüft man die verwendeten Datenstrukturen. Damit kann man oft mehr gewinnen. Der einfachste Ansatz wäre nämlich, dein $ausgabe-Array anders zu erzeugen. Du könntest die ID als Key verwenden, dann kannst Du auf $ausgabe[1] zugreifen und brauchst überhaupt keine Suche mehr. Ob das geht, hängt natürlich von deinem übrigen Programm ab und davon, ob die ID-Spalte eindeutige Werte enthält.

    Wenn Du die Erzeugung von $ausgabe nicht beeinflussen kannst oder willst, dann könntest Du es auch nachträglich in die Index-Form umbauen (mich wundert gerade, dass PHP sowas wie array_indexBy nicht mitbringt; ich finde nichts passendes...). Das lohnt aber nur, wenn Du das Ergebnis öfter brauchst, andernfalls ist das ineffizient.

    // Für deine Funktionensammlung
    function array_indexBy($array, $keyCol) {
       $result = [];
       foreach ($array as $entry)
          $result[$entry[$keyCol]] = $entry;
       return result;
    }
    
    // Da, wo Du die Ausgabe durchführst
    $ausgabe = array_indexBy($ausgabe, 'id');
    if (isset($ausgabe[1]))
       echo "<h1>{$ausgabe[1]['inhalt']}</h1>";
    

    Edit: Den von 1UP bemerkten Fehler korrigiert.

    Wenn Du die Existenz von ID 1 garantieren kannst, ist der isset Test nicht nötig.

    Wenn Du das Array nicht umbauen kannst oder willst, kannst Du alternativ folgendes tun:

    • Suchlogik und Ausgabe trennen
    • die Suchschleife als foreach eleganter formulieren und bei Treffer sofort verlassen

    Ersteres ist deshalb wichtig, weil ich annehmen würde, dass Du auch noch andere Anlässe hast, in einem Array dieser Art nach einer ID zu suchen. Letzteres dient der Performance.

    $ausgabeZeile = findeAusgabeId($ausgabe, 1);
    if ($ausgabeZeile !== FALSE) {
       echo "<h1>{$ausgabeZeile['inhalt']}</h1>";
    }
    
    // und in deiner Funktionensammlung:
    function findeAusgabeZeile($ausgabe, $id) {
       foreach ($ausgabe as $zeile) {
          if ($zeile['id'] == $id)
             return $zeile;
       }
       return FALSE;
    }
    

    Letztendlich könnte man diese letzte Funktion auch allgemeingültig formulieren; wundert mich eigentlich dass PHP sowas nicht an Bord hat...

    function array_findSubkey($array, $subKey, $value) {
       foreach ($array as $row) {
          if (isset($row[$subKey]) && $row[$subKey] == $value)
             return $row;
       }
       return FALSE;
    }
    
    // Aufruf:
    $ausgabeZeile = array_findSubkey($ausgabe, 'id', 1);
    

    Eine noch allgemeinere Variante wäre eine Implementierung von array_search mit einer Callback-Funktion; das lass ich jetzt mal 😀

    Rolf

    --
    sumpsi - posui - clusi
    1. // Für deine Funktionensammlung
      function array_indexBy($array, $keyCol) {
         $result = [];
         foreach ($array as $entry)
            $result[$keyCol] = $entry;
         return result;
      }
      

      Sollte da nicht $result[$entry[$keyCol]] = $entry stehen?

      1. Hallo 1unitedpower,

        Yup, fixed. Danke!

        Rolf

        --
        sumpsi - posui - clusi
    2. Eine noch allgemeinere Variante wäre eine Implementierung von array_search mit einer Callback-Funktion; das lass ich jetzt mal 😀

      Es gibt mit array_filter bereits eine Variante dieser Funktion. Sie gibt nicht nur das erste gefundene Elemente zurück, sondern alle passenden Elemente. Von da aus ist ein Leichtes an das erste Element zu kommen.