raphael90: Mehrere Vorkommen eines Strings in einem Array

Hi,

ich habe ein zweidimensionales Array, in dessen erstem Array Namen stehen und im zweiten ein dem Namen zugeordnetes Datum.
Ein Name kann aber in dem ersten Array auch mehrmals vorkommen, allerdings mit einem anderen Datum im zweiten Array.

Also z.B.

$test_arr[0][0] = "Max Mustermann";  
$test_arr[0][1] = "Anna Mustermann";  
$test_arr[0][2] = "Max Mustermann";

Dazu dann

$test_arr[1][0] = "1.2.";  
$test_arr[1][1] = "2.2.";  
$test_arr[1][2] = "3.2.";

Jetzt will ich aus diesem Array eine Tabelle erstellen, in der in der ersten Spalte der Name steht und in den weiteren Spalten alle zugehörigen Daten.

Ich habe es versucht mit

 $name = "Max Mustermann";  
 echo '<tr><td>'.$name.'</td>';  
 $pos1 = array_search($name, $test_arr[0]);  
 if ($pos1!=false) {  
  echo '<td>'.$test_arr[1][$pos1].'</td>';  
  
  $n_arr1 = array_slice($test_arr[0], $pos1+1);  
  $pos_2 = array_search($name, $n_arr1);  
  if ($pos_2!=false) {  
   $pos2=$pos_2+$pos1+1;  
   echo '<td>'.$test_arr[1][$pos2].'</td>';  
  
   $n_arr2 = array_slice($test_arr[0], $pos2+1);  
   $pos_3 = array_search($name, $n_arr2);  
   if ($pos_3!=false) {  
    $pos3=$pos_3+$pos2+1;  
    echo '<td>'.$test_arr[1][$pos3].'</td>';  
  
    $n_arr3 = array_slice($test_arr[0], $pos3+1);  
    $pos_4 = array_search($name, $n_arr3);  
    if ($pos_4!=false) {  
     $pos4=$pos_4+$pos3+1;  
     echo '<td>'.$test_arr[1][$pos4].'</td>';  
  
    } else { echo '<td>&nbsp;</td>'; }  
   } else { echo '<td>&nbsp;</td>'; }  
  } else { echo '<td>&nbsp;</td>'; }  
 } else { echo '<td>&nbsp;</td>'; }  
 echo '</tr>';

Aber da gibt es doch sicherlich eine sauberere Lösung, oder?

Viele Grüße, Raphael

  1. Lieber raphael90,

    vielleicht ist es sinnvoller, eine andere Array-Struktur zu benutzen?

    Mein Vorschlag:

    $test_arr = array (  
        0 => array(  
            'name' => 'Max Mustermann',  
            0      => '1.2.',  
            1      => '3.2'  
        ),  
      
        1 => array(  
            'name' => 'Anna Mustermann',  
            0 => '2.2'  
        ),  
      
        2 => array(  
            'name' => 'Fritz Mustermann',  
            0 => '4.2',  
            1 => '5.2'  
        )  
    );
    

    Nun kannst Du davon ausgehen, dass wenn Du einen Namen hast (sprich ein Array innerhalb von $test_arr), dass dort alle möglichen Daten gesammelt sind, sodass Du in der Tabelle alle Daten beieinander hast.

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Hallo Felix,
      vielen Dank erstmal für die schnelle Antwort.

      vielleicht ist es sinnvoller, eine andere Array-Struktur zu benutzen?

      Ja, klingt sinnvoll. Da muss ich zwar im vorigen Script noch einiges umstellen, das war aber sowieso nötig.

      Mein Vorschlag:

      $test_arr = array (

      0 => array(
              'name' => 'Max Mustermann',
              0      => '1.2.',
              1      => '3.2'
          ),

      1 => array(
              'name' => 'Anna Mustermann',
              0 => '2.2'
          ),

      2 => array(
              'name' => 'Fritz Mustermann',
              0 => '4.2',
              1 => '5.2'
          )
      );

      
      >   
      
      Ich muss noch dazusagen:  
      An einem Tag können auch mehrere Namen vorkommen.  
      Und es sind ca. 60 Namen vorhanden, das dürfte ja aber eigtl. kein Problem sein.  
        
      Könnte ich jetzt auch aus deinem Vorschlags-Array irgendwie auslesen, wo welches Datum steht?  
      Also mit soetwas wie array\_search, das mir dann z.B. [0][1] ausgibt?  
        
      Viele Grüße,  
      Raphael
      
      1. Lieber raphael90,

        grundsätzlich kannst Du Dein Array nach Datum oder nach Namen geordnet anlegen. Das ist zunächst einmal völlig egal.

        ABER: Wenn Du später die Informationen nach Namen sortiert ausgeben willst, andere Nutzungen derselben Daten dabei nicht beabsichtigt sind, dann ist es zweckmäßig, das Array nach Namen sortiert anzulegen. Da Deine Namen sich als Array-Schlüssel nicht eignen (wegen Leer- und Sonderzeichen), bietet es sich an, für jeden Namen ein eigenes Array anzulegen, in dem der Index "name" den Namen transportiert, und in dem die folgenden (numerischen) Indices das jeweilige Datum tragen.

        Eine nach Datum sortierte Array-Struktur ist selbstverständlich ebenfalls möglich, nur musst Du dann eben bei der nach Namen sortierten Ausgabe jedesmal durch das Array hindurchsieben, ob der jeweilige Name am gerade betroffenen Tagesdatum gespeichert ist - im Grunde nur der andere Weg um denselben See herum.

        Was meinen Vorschlag mit den numerischen Indices für die Daten angeht:

        array(  
            'name' => 'Max Mustermann',  
            '20090301' => '03.01.2009',  
            '20090401' => '04.01.2009'  
        )
        

        Du kannst das Tagesdatum in der Form YYYYMMDD als Array-Index einsetzen...

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  2. echo $begrüßung;

    ich habe ein zweidimensionales Array, in dessen erstem Array Namen stehen und im zweiten ein dem Namen zugeordnetes Datum.
    Ein Name kann aber in dem ersten Array auch mehrmals vorkommen, allerdings mit einem anderen Datum im zweiten Array.

    Also z.B.

    $test_arr[0][0] = "Max Mustermann";

    $test_arr[0][1] = "Anna Mustermann";
    $test_arr[0][2] = "Max Mustermann";

    
    >   
    > Dazu dann  
    > ~~~php
    
    $test_arr[1][0] = "1.2.";  
    
    > $test_arr[1][1] = "2.2.";  
    > $test_arr[1][2] = "3.2.";
    
    

    Jetzt will ich aus diesem Array eine Tabelle erstellen, in der in der ersten Spalte der Name steht und in den weiteren Spalten alle zugehörigen Daten.

    Dazu kannst du deine Daten einerseits nach den Namen sortieren, so dass gleiche Namen hintereinander stehen, und anschließend mit einem so genannten Gruppenwechsel bei der Ausgabe arbeiten. Beim Sortieren des ersten Arrays solltest du die Schlüssel-zu-Wert-Zuordnung beibehalten und anschließend mit foreach (... as $key => $value) darüber laufen. Dann kannst du über den Key auf den Key des Datums im zweiten Feld zugreifen. Wenn sich bei einem Schleifendurchlauf der Name zum vorhergehenden Durchlauf ändert, hast du den Wechsel und schließt die eine Zeile ab und eröffnest die nächste. Diese Vorgehensweise hat den Nachteil, dass du am Ende eine offene Zeile übrig hast oder aber stets testen musst, ob du am Ende angelangt bist.

    Die zweite Möglichkeit ist das Umsortieren nach Felix' Vorschlag. Seine Aussage, dass sich Werte mit Sonder- und Leerzeichen nicht als Schlüssel eignen, ist nicht richtig, denn als Key kann jeder Integer-Wert und String ohne weitere Einschränkungen verwendet werden.

    Deshalb kann man das Array mit einfacherer Struktur erzeugen:

    $array = (  
      'Max Mustermann' => array('1.2.', '3.2.'),  
      'Anna Mustermann' => array('2.2'));
    

    Das Umsortieren in diese Form ist nicht sehr schwer. Bei jedem Namen aus Array 1 wird mit isset() nachgeschaut, ob er schon als Key existiert und dann das Datum an das Array angefügt. Wenn nicht, ist ein neues Array mit dem Datum als Element zu erstellen.

    Einen sich wiederholenden Text mit Array-Werten dazwischen zu erstellen kann man mit implode() erledigen. Ein

    implode('</td><td>', $werte_array)

    ergibt

    wert 1</td><td>wert 2</td><td>wert 3 usw.

    An den Anfang ein <td> und ans Ende ein </td> und fertig ist der Zeileninhalt. Nicht ganz, denn in deinem Fall muss noch eine Zelle mit dem Namen vorndran und gegebenenfalls müssen auch noch Leerzellen angehängt werden, deren Anzahl sich aus der Differenz der Anzahl der Datumswerte und einer von dir festgelegten Spaltenanzahl ergibt. Mit str_repeat() lassen sie sich ohne großen Aufwand erzeugen. Den fertigen Zeileninhalt kannst zu in einem weiteren Array zwischenablegen, das du auf die gleiche Weise mit implode() zur fast fertigen Tabelle zusammenbauen lassen kannst.

    $pos1 = array_search($name, $test_arr[0]);
    if ($pos1!=false) {

    Das ist nicht richtig, denn auch der Wert 0 entspricht beim Vergleichen einem false. Ein typenechter Vergleich mit !== führt zum Ziel. Ansonsten ist der Code leider wieder einer aus der Kategorie "unkommentierter Codehaufen". Du tust dir und allen anderen, die das Notierte lesen sollen, keinen Gefallen, wenn du nicht dazu schreibst, was es bezweckt. Aus einem Code selbst auf seine Aufgabe und seine Wirkungsweise zu schließen ist nicht unbedingt erbauend und dürfte bei den wenigsten Programmierern zu deren Lieblingstätigkeiten zählen, besonders nicht, wenn er nicht fehlerfrei ist.

    Bei jedem Code, der sich wiederholt ist es überlegenswert, ob man nicht die ewig gleichen Teile in eine Funktion auslagert und nicht x Mal hinschreibt. Bei einer Änderung muss man nur die Funktion anpassen und nicht zig Kopieen.

    echo "$verabschiedung $name";

    1. echo $begrüßung;

      na dann doch gleich echo $floskel[0]; :)

      Dazu kannst du deine Daten einerseits nach den Namen sortieren, so dass gleiche Namen hintereinander stehen, und anschließend mit einem so genannten Gruppenwechsel bei der Ausgabe arbeiten. Beim Sortieren des ersten Arrays solltest du die Schlüssel-zu-Wert-Zuordnung beibehalten und anschließend mit foreach (... as $key => $value) darüber laufen. Dann kannst du über den Key auf den Key des Datums im zweiten Feld zugreifen. Wenn sich bei einem Schleifendurchlauf der Name zum vorhergehenden Durchlauf ändert, hast du den Wechsel und schließt die eine Zeile ab und eröffnest die nächste. Diese Vorgehensweise hat den Nachteil, dass du am Ende eine offene Zeile übrig hast oder aber stets testen musst, ob du am Ende angelangt bist.

      Jaaaa, das ist es, was ich gesucht habe, super, vielen Dank!
      Nur was ich noch nicht ganz verstehe, wie ich diesen Gruppenwechsel untersuchen kann. Kannst du mir bitte dafür evtl noch ein Beispiel posten?

      Das Umsortieren in diese Form ist nicht sehr schwer. Bei jedem Namen aus Array 1 wird mit isset() nachgeschaut, ob er schon als Key existiert und dann das Datum an das Array angefügt. Wenn nicht, ist ein neues Array mit dem Datum als Element zu erstellen.

      Da muss ich jetzt ausprobieren, welche der Varianten für meinen Fall geeigneter ist.

      Ein typenechter Vergleich mit !== führt zum Ziel.

      Das habe ich schon immer falsch gemacht, sorry...

      Ansonsten ist der Code leider wieder einer aus der Kategorie "unkommentierter Codehaufen". Du tust dir und allen anderen, die das Notierte lesen sollen, keinen Gefallen, wenn du nicht dazu schreibst, was es bezweckt. Aus einem Code selbst auf seine Aufgabe und seine Wirkungsweise zu schließen ist nicht unbedingt erbauend und dürfte bei den wenigsten Programmierern zu deren Lieblingstätigkeiten zählen, besonders nicht, wenn er nicht fehlerfrei ist.

      Oh schreibt man üblicherweise zu dem Code immer Kommentare?
      Erhöht das nicht "unnötig" (wenns dann mal läuft) die Datengröße?

      echo "$verabschiedung $name";

      Na denn, echo $floskel[1];

      1. echo $begrüßung;

        Dazu kannst du deine Daten einerseits nach den Namen sortieren, so dass gleiche Namen hintereinander stehen, und anschließend mit einem so genannten Gruppenwechsel bei der Ausgabe arbeiten. Beim Sortieren des ersten Arrays solltest du die Schlüssel-zu-Wert-Zuordnung beibehalten und anschließend mit foreach (... as $key => $value) darüber laufen. Dann kannst du über den Key auf den Key des Datums im zweiten Feld zugreifen. Wenn sich bei einem Schleifendurchlauf der Name zum vorhergehenden Durchlauf ändert, hast du den Wechsel und schließt die eine Zeile ab und eröffnest die nächste. Diese Vorgehensweise hat den Nachteil, dass du am Ende eine offene Zeile übrig hast oder aber stets testen musst, ob du am Ende angelangt bist.
        Jaaaa, das ist es, was ich gesucht habe, super, vielen Dank!
        Nur was ich noch nicht ganz verstehe, wie ich diesen Gruppenwechsel untersuchen kann. Kannst du mir bitte dafür evtl noch ein Beispiel posten?

        Das schrieb ich ja eigentlich schon. Hier nochmal ausführlich: Du merkst dir am Anfang den ersten Wert. Beim jedem Durchlauf untersuchst du, ob sich der gemerkte Wert zum aktuellen Namen unterscheidet. Das ist dann der Wechsel.

        $array = array(1,1,2,3,3); // ein Array mit Beispieldaten  
          
        $current = reset($array); // ersten Wert des Arrays ermitteln  
          
        echo "<p>\n"; // Eine Ausgabe am Anfang  
        foreach ($array as $value) {  
          if ($current != $value) { // wird in diesem Beispiel true bei 2 und bei der ersten 3  
            $current = $value; // neuen aktuellen Wert merken  
            echo "<br>\n"; // Ausgabe, die beim Wechsel erfolgen soll, also zwischen zwei Gruppen stehen soll  
          }  
          echo $value; // Ausgabe des Wertes, zuzüglich weiterer Formatierungen und dergleichen  
        }  
        echo "</p>\n"; // Eine Ausgabe am Ende
        

        Außerdem war mein letzter Satz aus obigem Zitat nicht richtig. Em Ende findet ja kein Wechsel mehr statt, weil schlicht und einfach nichts mehr kommt, was noch wechseln kann.

        Das Umsortieren in diese Form ist nicht sehr schwer. Bei jedem Namen aus Array 1 wird mit isset() nachgeschaut, ob er schon als Key existiert und dann das Datum an das Array angefügt. Wenn nicht, ist ein neues Array mit dem Datum als Element zu erstellen.

        Da muss ich jetzt ausprobieren, welche der Varianten für meinen Fall geeigneter ist.

        Nachdem ich meinen Irrtum bemerkt habe, denke ich heute, dass die erste Variante diejenige der Wahl sein sollte. Du musst nur die Namen sortieren und kannst dann gleich die Ausgabe vornehmen. Variante zwei erfordert erst ein Umsortieren und das Zwischenspeichern.

        Ein typenechter Vergleich mit !== führt zum Ziel.
        Das habe ich schon immer falsch gemacht, sorry...

        Kein Grund sich bei mir zu entschuldigen :-)

        Oh schreibt man üblicherweise zu dem Code immer Kommentare?
        Erhöht das nicht "unnötig" (wenns dann mal läuft) die Datengröße?

        Du sollst ja nur mehr oder weniger kurze Kommentare und keine Gigabyte-schwere Dokumentation schreiben. Das Ignorieren der Kommentare ist für den Parser kein großes Thema. Der Zeitverlust sollte nicht ins Gewicht fallen. Viel wichtiger ist jedoch ihr Beitrag zum Verständnis, reduziert sie doch die Zeit, die für die Wartung aufgebracht werden muss, und die ist deutlich länger und teurer. Genausogut könntest du deine Variablennamen auf wenige Buchstaben verkürzen wollen. Auch das trägt nicht zum Verständnis und kaum zur Geschwindigkeit bei. Die Datengröße ist auch nicht wichtig, denn das Übertragen zum Server ist ja ein einmaliger Vorgang. Weitere Übertragungen finden ja nicht statt. Der auf dem Server benötigte Plattenplatz ist ebenfalls vernachlässigbar.

        echo "$verabschiedung $name";

        1. Hallo nochmal,

          FERIG!

          Vielen Dank nochmal für eure Hilfe, jetzt ist es mir gelungen, das Projekt genau so zu verwirklichen, wie ich es mir vorgestellt habe :)

          Immer wieder ein schönes Gefühl...

          Viele Grüße, Raphael