WernerK: PHP Strings zusammenführen?

Hallo,

angenommen man hätte nach einem foreach Durchlauf folgende zwei Strings:

10:00;;;;;;;
;;;17:00;;;;

Gibt es einen Trick diese zusammenzuführen zu einer Zeile?

10:00;;;17:00;;;;

Hintergrund: Die Daten kommen aus einer DB und haben unterschiedliche Zeilen. Wenn die Main ID / Flag gleich ist in den Zeilen, dann sollen diese Uhrzeiten in einer einzigen Zeile später verwendet werden.

Danke

Gruss

Werner

  1. Hallo WernerK,

    ich habe in deinem Posting den Code-Teil mal in ~~~ eingeschlossen.

    Was Du bräuchtest, ist so eine Art "COALESCE" auf Array-Element Ebene (dafür musst Du den String vorher mit explode in ein Array umwandeln). Eine fertige PHP Funktion dafür kenne ich nicht, aber das ist doch eigentlich relativ leicht geschrieben.

    Ein Problem entsteht nur, wenn in zwei Zeilen in der gleichen Spalte einen Wert vorfindest? Kann das passieren? Wie muss man damit umgehen?

    Frage wäre auch, ob es denn ein Semikolon-separierter String sein muss. Wenn die Daten aus einer DB stammen, könnte man das ggf. per SQL lösen (mit GROUP BY und MAX)

    Rolf

    --
    sumpsi - posui - clusi
  2. Tach!

    angenommen man hätte nach einem foreach Durchlauf folgende zwei Strings:

    10:00;;;;;;;
    ;;;17:00;;;;
    

    Ob foreach oder was anderes, ist erstmal nicht relevant. Da wären also zwei Strings. Wenn die aus Elementen bestehen, wäre der erste Schritt, diese Strings in ihre Elemente zu zerlegen. explode() am Semikolon bietet sich hier an. Damit hat man wei Arrays. Mit for(each) lässt sich dann recht einfach auf die einzelnen Elemente zugreifen, einfacher als mit Stringoperationen.

    Gibt es einen Trick diese zusammenzuführen zu einer Zeile?

    10:00;;;17:00;;;;
    

    Als erstes braucht es ein weiteres, zunächst leeres Array, um das Ergebnis aufzunehmen.

    Unter der Annahme, dass beide Strings gleich viele Elemente enthalten, kann man nun ein beliebiges der beiden Arrays nehmen, darüber mit for (und einem Hilfsindex, gemeinhin i) iterieren und das aktuelle Element mit dem an gleicher Position im anderen Array vergleichen, um zu entscheiden, welches man haben möchte. Das fügst du dem Ergebnis-Array hinzu. Am Ende kann das Ergebnis-Array zu einem String implode()iert werden.

    Wenn die Arrays unterschiedliche Länge haben, muss zunächst das längere ermittelt werden. Darüber muss dann die for-Schleife laufen. Oder man nimmt das kürzere, wenn die überzähligen Elemente des anderen nicht interessieren. Der Rest bleibt gleich.

    dedlfix.

  3. Hallo,

    Gibt es einen Trick diese zusammenzuführen zu einer Zeile?

    10:00;;;17:00;;;;
    

    Ich weiß nicht ob ich hier nicht kompliziert genug denke oder die anderen Antworter zu kompliziert. Daher mal ins Blaue:

    Du hast 2 Strings. Also

    $a = '10:00;;;;;;;';
    $b = ';;;17:00;;;;';
    
    $c = $a.$b; 
    

    Ausgabe $c entspricht: 10:00;;;;;;17:00;;;;

    lg.

    1. Komisch, wollte zum 2ten mal bearbeiten, ging nicht, dann wollte ich einen kurzen Nachtrag machen, kamm Entwurf, war verwirrt, daher hier 2 mal post.

    2. Ach so nochwas, falls die unerwünschte Ausgabe aus anderen Gründen so erscheint, könnte auch noch ein verstecktes Absatzzeichen drin sein. Daher immer gut, wenn Werte mit trim() behandelt werden.

    3. Hallo,

      Ich weiß nicht ob ich hier nicht kompliziert genug denke oder die anderen Antworter zu kompliziert.

      Ja, dachte ich auch zuerst. Es geht aber nicht ums Aneinanderhängen, sondern ums Zusammenführen.

      Gruß
      Kalk

      1. Hallo

        Ich weiß nicht ob ich hier nicht kompliziert genug denke oder die anderen Antworter zu kompliziert.

        Ja, dachte ich auch zuerst.

        Da wart ihr nicht die einzigen.

        Es geht aber nicht ums Aneinanderhängen, sondern ums Zusammenführen.

        Ich frage mich, warum die Daten, wo sie doch aus einer DB kommen, überhaupt in einer für den gewünschten Zweck so ungünstigen Form vorliegen.

        Tschö, Auge

        --
        Ein echtes Alchimistenlabor musste voll mit Glasgefäßen sein, die so aussahen, als wären sie beim öffentlichen Schluckaufwettbewerb der Glasbläsergilde entstanden.
        Hohle Köpfe von Terry Pratchett
        1. Hallo Auge,

          nicht ganz so einfach zu erklären:

          Es werden pro Woche bestimmte Zeiten für eine Aufgabe gespeichert. Die stehen dann halt hintereinander in einer Tabelle weil die einzelnen Tage und Zeiten später wieder in einem Kalender angezeigt werden.

          In einer späteren Ausgabe als PDF sollen aber die Wochentage pro Aufgabe in einer Zeile dargestellt werden.

          Mo,    Di, Mi, Do, Fr,    Sa,   So
          
          10:00              17:00        11:00
          

          Gruesse

          Werner

          1. Hallo

            Es werden pro Woche bestimmte Zeiten für eine Aufgabe gespeichert. Die stehen dann halt hintereinander in einer Tabelle

            Das riecht mir nach einer Zeichenkette mit allen Werten, die in einem Feld in der Tabelle steht; also nach ungenügender Normalisierung. Oder verrieche ich mich?

            Tschö, Auge

            --
            Ein echtes Alchimistenlabor musste voll mit Glasgefäßen sein, die so aussahen, als wären sie beim öffentlichen Schluckaufwettbewerb der Glasbläsergilde entstanden.
            Hohle Köpfe von Terry Pratchett
            1. Hallo Auge,

              es ist nicht gut, wenn ein Auge riechen muss. Besser wär's, es könnte was sehen.

              Werner? Welches Table-Layout das?

              Und auf meine Frage, was die Konsolidierung tun soll, wenn in einer Spalte mehr als ein Wert steht, habe ich auch noch keine Antwort gesehen (oder übersehen?). Oder ist das durch die Business Logik ausgeschlossen?

              Rolf

              --
              sumpsi - posui - clusi
              1. @@Rolf B

                Hallo Auge,

                es ist nicht gut, wenn ein Auge riechen muss. Besser wär's, es könnte was sehen.

                „Milz an Auge: Ich sehe was, was du nicht siehst!“

                LLAP 🖖

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

    ich habe nochmal geschaut - was Du brauchst, ist in PHP eigentlich bereits vorhanden, nämlich array_map. Dem kann man nicht nur ein Array übergeben, sondern mehrere. array_map durchläuft diese Arrays parallel und übergibt die Werte an die Callback-Funktion.

    Beispiel:

    $a = ARRAY(1,2,3);
    $b = ARRAY(11,12,13,14);
    $c = ARRAY(21,22,23);
    
    array_map("myCallback", $a, $b, $c);
    

    Von array_map wird die Funktion myCallback nun vier mal aufgerufen.

    Aufruf 1: myCallback(1,11,21);
    Aufruf 2: myCallback(2,12,22);
    Aufruf 3: myCallback(3,13,23);
    Aufruf 4: myCallback(null,14,null);

    Ergebnis ist ein Array, das aus den vier Rückgabewerten von myCallback besteht.

    Angewendet auf deine Aufgabenstellung denke ich mir, dass es ein Sonderfall ist, dass Du nur zwei Strings hast, die Du zusammenmischen willst. Im Allgemeinen wird das ein Array aus 1-N Strings sein. Nennen wir es mal $results.

    Herausforderung 1 ist demnach, array_map mit einer variablen Anzahl von Parametern aufzurufen. Das ist seit PHP 5.6 relativ einfach geworden, man verwendet den Operator "...". Vorher hätten wir ein temporäres Array aufbauen und call_user_func_array verwenden müssen.

    Die Parameter für array_map müssen wir noch aufbereiten. Du hast Strings, in denen die Werte mit Semikolon getrennt sind, das müssen Arrays werden. Wie schon geschrieben, dient dazu explode. Wir müssen also ein Array aus Strings in ein Array aus explodierten Strings umwandeln - wieder eine Aufgabe für array_map:

    function explode_result($aString) {
       return explode(";", $aString);
    }
    $results_as_array = array_map("explode_result", $results);
    

    Damit können wir nun array_map aufrufen, um die Werte zu konsolidieren:

    $consolidated_result 
        = array_map("coalesce_values", ...$results_as_array);
    

    Hier wird der ... Operator in seiner Funktion als "Spread"- oder "Splat"-Operator benutzt: er verteilt das Array auf seine einzelnen Werte. Bei 3 Einträgen in $results_as_array würde array_map 4 Parameter übergeben bekommen.

    coalesce_values ist der Name der Funktion, die array_map als Callback aufrufen soll. Diese Funktion enthält Herausforderung 2, wir wissen ja nicht, wieviele Arrays wir an array_map übergeben, und darum wissen wir nicht, wieviele Parameter die Callbackfunktion bekommt. Auch hier hilft der ... Operator, diesmal als "Rest"-Operator, der alle Parameter in einem Array einsammelt (hier steht mehr dazu).

    function coalesce_values(...$werte) {
       foreach ($werte as $wert)
          if ($wert !== null && $wert !== "") return $wert;
       return "";
    }
    

    Was coalesce_values tut, sollte offensichtlich sein: sie durchläuft die übergebenen Werte und gibt den ersten zurück, der nicht NULL oder "" ist. Gibt es keinen, wird "" zurückgegeben.

    Das ist alles. Nochmal alles zusammengefasst:

    $results_as_array = array_map("explode_result", $results);
    
    $consolidated_result 
        = array_map("coalesce_values", ...$results_as_array);
    
    function explode_result($aString) {
       return explode(";", $aString);
    }
    
    function coalesce_values(...$werte) {
       foreach ($werte as $wert)
          if ($wert !== null && $wert !== "") return $wert;
       return "";
    }
    

    Auf Aspekte funktionaler Programmierung, die man hier für die Callbacks anbringen könnte, habe ich bewusst verzichtet.

    Rolf

    --
    sumpsi - posui - clusi