Peter Goss: 2 Arrays vergleichen

Hallo Leute!

Ich bastle nun schon fast eine Woche an einem Perl-Script, was ich unbedingt bis Mittwoch endgültig zum Laufen gebracht haben muß. Vielleicht liegt es an der Uhrzeit oder den vielen Subscripts, die ich schon geschrieben habe, aber ich hab für folgendes Problem einfach keine Lösung.

Ich habe 2 Textdateien, die ich jeweils in 1 Array einlese. Hier mal ein Beispiel:

text1.txt:
1;PE12345
40;PE234
12;IK3210

text2.txt:
3;AK567
2;PE12345
20;IL098
6;JJ234567

Es handelt sich um 2 unterschiedliche Dateien, also die Eintragsanzahl je Datei kann vollkommen variieren,jedoch ist der Aufbau immer der selbe - an 1. Stelle immer eine Mengenanzahl und an 2. Stelle eine Registriernummer, jeweils mit einem Semikolion getrennt.

Ich möchte nun mittels eines Perl-Scriptes die beiden eingelesen Arrays miteinander vergleichen und in eine neue Datei zusammenfassen. Ist eine Registriernummer doppelt vergeben, sollen die beiden Mengen miteinander addiert werden und in die neue Datei gespeichert werden. Die anderen Einträge, also deren Registernummer nicht identisch sind, sollen aus beiden Dateien ebenfalls in die neue geschrieben werden.

Ich habe schon zahlreiche Versuche durchgespielt, aber leider erfüllt keiner seinen Zweck. Ich hoffe, von euch kann mir jemand helfen.

Ciao
Peter

  1. Hallo Peter,

    Ich habe schon zahlreiche Versuche durchgespielt, aber leider erfüllt
    keiner seinen Zweck. Ich hoffe, von euch kann mir jemand helfen.

    Zuerst musst du die Dateien in eine verwertbare Form ueberfuehren:

    my ($file1,$file2) = ({},{});

    read_file('datei1',$file1);
    read_file('datei2',$file2);

    sub read_file {
      my $filename = shift;
      my $ref      = shift;

    open DAT,'<'.$filename or die $!;

    while(<DAT>) {
        chomp;
        next unless m!^(\d+);(.*)$!;

    $ref->{$2} = $1;
      }

    close DAT;
    }

    Dann kannst du das ganze sehr einfach vergleichen:

    my $merged = {};

    foreach my $hash ($file1,$file2) {
      foreach my $key (keys %{$hash}) {
        $merged->{$key}  = 0 unless exists $merged->{$key};
        $merged->{$key} += $hash->{$key};
      }
    }

    Die Keys sind die Serien-Nummern, die Values die Anzahl.

    Grüße,
     CK

    --
    Es gibt keinen Ort, wo der Geist zu finden waere. Er ist wie die Fussspuren der Voegel am Himmel.
  2. Moin!

    text1.txt:
    1;PE12345
    40;PE234
    12;IK3210

    text2.txt:
    3;AK567
    2;PE12345
    20;IL098
    6;JJ234567

    Hm.... Du musst einfach Dich einfach nur ganz dumm stellen und Dir vorstellen, Du wärst ein fürchterlicher Bürokrat...  ich schreib Dir die Lösung mal in fastix® - Code :)

    Einlesen der Textdateien in arrays. (Array1, Array2)

    für jedes Element in Array1 {
       trenne am ";" -> $anzahl1 , $rnr1;
       für jedes Element in Array2 {
          trenne am ";" -> $anzahl2 , $rnr2;
          if ($rnr1==$rnr2) {
              $anzahl1=$anzahl1+$anzahl2;
              Element in Array2 löschen # (sic!)
          }
          Anhängen von $anzahl1; $rnr1 an neue Datei (oder Array)
       }
    } #  es bleiben die Elemente in Array2, die keine Übereinstimmumg in Array1 hatten
    für jedes Element in Array2 {
       trenne am ";" -> $anzahl2 , $rnr2;
       if (rnr2>0) {
          Anhängen von von $anzahl1; $rnr1 an neue Datei (oder Array)
       }
    }

    eventuell Schreiben des Arrays in eine Datei...

    fertig

    MFFG (Mit freundlich- friedfertigem Grinsen)

    fastix®

    --
    Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Development. Auch  für seriöse Agenturen.
    1. Moin!

      Einlesen der Textdateien in arrays. (Array1, Array2)

      für jedes Element in Array1 {
         trenne am ";" -> $anzahl1 , $rnr1;
         für jedes Element in Array2 {
            trenne am ";" -> $anzahl2 , $rnr2;
            if ($rnr1==$rnr2) {
                $anzahl1=$anzahl1+$anzahl2;
                Element in Array2 löschen # (sic!)
            } # end if
         } # next element
         Anhängen von $anzahl1; $rnr1 an neue Datei (oder Array);
      } #  es bleiben die Elemente in Array2, die keine Übereinstimmumg in Array1 hatten
      für jedes Element in Array2 {
         trenne am ";" -> $anzahl2 , $rnr2;
         if (rnr2>0) {
            Anhängen von von $anzahl1; $rnr1 an neue Datei (oder Array)
         }
      }

      eventuell Schreiben des Arrays in eine Datei...

      fertig

      Da war eine Zeile verrutscht.

      MFFG (Mit freundlich- friedfertigem Grinsen)

      fastix®

      --
      Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Development. Auch  für seriöse Agenturen.
      1. hi fastix®!

        danke, so in etwa habe ich mir das in etwa auch gedacht, nur auf die idee mit dem elementlöschen aus dem array ist mir nicht gekommen.

        Element in Array2 löschen # (sic!)

        hm, da hab ich das nächste problem. :( wie kann ich feststellen, welchen teil des arrays er in "foreach" gerade durchläuft, um es an "splice" zu übergeben?

        1. Moin!

          wie kann ich feststellen, welchen teil des arrays er in "foreach" gerade durchläuft, um es an "splice" zu übergeben?

          Ich als alter BASIC- Programmierer gehe immer am liebsten Fußwege.
          Ich baue ungern diese foreach- Schleifen...

          Gefunden auf: http://www.perldoc.com/perl5.8.0/pod/perlintro.html#Conditional-and-looping-constructs

          foreach (@array) {
                  print "This element is $_\n";
             # Hier ist, was Du suchst:  ^^
              }

          MFFG (Mit freundlich- friedfertigem Grinsen)

          fastix®

          --
          Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Development. Auch  für seriöse Agenturen.
          1. Moin!

            oder halt so:

            $intCounter=(-1);
                 foreach (@array) {
                     $intCounter++;   # <- Da ist, was Du suchst.

            }

            MFFG (Mit freundlich- friedfertigem Grinsen)

            fastix®

            --
            Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Development. Auch  für seriöse Agenturen.
            1. Hallo fastix®,

              $intCounter=(-1);

              Bitte nicht.

              my $intCounter = -1;

              (-1) hat einen anderen Sinn als -1. Stichwort: Listen-Kontext.

              Ansonsten sollte der OP einfach mal einen Blick auf meine Loesung
              werfen... ;)

              Grüße,
               CK

              --
              Wenn auf Erden alle das Schoene als schoen erkennen, so ist dadurch schon das Haessliche bestimmt.
              1. Hallo fastix®,

                Ansonsten sollte der OP einfach mal einen Blick auf meine Loesung
                werfen... ;)

                Nur, um das klarzustellen: das sollte er tun, weil meine Lösung einen
                linearen Aufwand hat, während deine Lösung aufgrund des splice() nicht
                mehr linear ist.

                Grüße,
                 CK

                --
                Sein oder nicht sein, das ist hier die Frage!
                1. Moin!

                  Hallo fastix®,

                  Deine sieht auch viel schöner aus. Im Ernst: Ich wollte eigentlich nur den Weg zeigen. Deswegen dieses fastix® - Script, welches eigentlich viel eher als Kommentar geeignet wäre. Mit Sicherheit lassen noch performantere Wege finden, zum Beispiel, wenn man die Array erstmal (extern... -> da war doch was) sortiert und dann die Durchläufe entsprechend abbricht. Aber
                  a) war ich ziemlich müde
                  b) wollte ich mich genau deswegen nicht mehr in die Sytax reindenken

                  MFFG (Mit freundlich- friedfertigem Grinsen)

                  fastix®

                  --
                  Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Development. Auch  für seriöse Agenturen.
          2. Hallo fastix®,

            Ich als alter BASIC- Programmierer gehe immer am liebsten Fußwege.
            Ich baue ungern diese foreach- Schleifen...

            Das solltest du ueberdenken. foreach-Schleifen sind idR um einiges
            performanter als diese sog. 'Fußwege'.

            Grüße,
             CK

            --
            Beware Evildoers for my deed is done and every little damsel in distress will be shelted!
  3. Moin!

    text1.txt:
    1;PE12345
    40;PE234
    12;IK3210

    text2.txt:
    3;AK567
    2;PE12345
    20;IL098
    6;JJ234567

    Ich möchte nun mittels eines Perl-Scriptes die beiden eingelesen Arrays miteinander vergleichen und in eine neue Datei zusammenfassen. Ist eine Registriernummer doppelt vergeben, sollen die beiden Mengen miteinander addiert werden und in die neue Datei gespeichert werden. Die anderen Einträge, also deren Registernummer nicht identisch sind, sollen aus beiden Dateien ebenfalls in die neue geschrieben werden.

    Gehe ich recht in der Annahme, dass das in die neue Datei auszugebende Resultat (basierend auf obigen Daten, ergänzt durch meine Kommentare - die kommen natürlich nicht mit raus) so aussehen soll:

    neutext.txt
    3;PE12345   -> 2+1
    40;PE234
    12;IK3210
    3;AK567
    20;IL098
    6;JJ234567

    Sortierung ist egal?

    Dann ist dein Problem kein "Array vergleichen"-Problem, sondern lediglich ein "Werte summieren"-Problem.

    Zur Lösung eignet sich die Verwendung eines Hashes. Der Hash kriegt als Schlüssel deine Identifikationsnummer, und als enthaltenen Wert die Anzahl.

    Auf diese Weise kannst du ganz einfach eine Datei nach der anderen auslesen und in den Hash füttern, und am Ende wiederum den Hash auslesen und in eine neue Datei füttern.

    Also als Beispiel:

    für alle Dateien (
      öffne Datei
      solange kein Dateiende (
        lies eine Zeile.
        splitte am ; -> ergibt $anzahl und $index
        $hash[$index] = $hash[$index] + $anzahl
      )
    )

    für alle Schlüsselwerte in %hash (
      gib $anzahl und $index aus
    )

    Ja, alles in Pseudocode, aber ich schätze mal, du bist des Programmierens mächtig. Und bevor ich hier böse Perl-Fehler bastel oder my-Deklarationen vergesse, lasse ich es lieber (Perl ist nicht meine bevorzugte Programmiersprache).

    - Sven Rautenberg

    --
    Die SelfHTML-Developer sagen Dankeschön für aktuell 21205,05 Euro Spendengelder!
    1. Hallo Sven,

      [... Hash-Loesung ...]

      [pref:t=68804&m=395246]

      Nächste mal einfach alle Postings im Thread lesen ;)

      Grüße,
       CK

      --
      Der Verstand steht ueber allem. Was durch die Vorstellungskraft nicht geschaffen werden kann, existiert nicht.
      1. Moin!

        [... Hash-Loesung ...]

        [pref:t=68804&m=395246]

        Nächste mal einfach alle Postings im Thread lesen ;)

        Ich hab dein Posting sehr wohl gelesen. Sogar vor meinem Posting.

        Dennoch denke ich, dass deine Lösung zwar vom Perl-Eleganz-Standpunkt aus einige Punkte machen würde, aber dennoch keine "gute Lösung[TM]" ist.

        Die für Normalbenutzer absolut unverständlichen Perlismen mal außen vor gelassen - die sind ein Thema für sich, und vermutlich einer der Gründe, warum PHP so beliebt ist - , sehe ich in deiner Lösung die zentrierte Sicht auf zwei Dateien.

        Nun kann man zwar jedes Problem von "mehrere Dateien zusammenfassen" zurückführen auf "Fasse die ersten zwei Dateien zusammen, und mache das Ergebnis zur neuen ersten Datei deiner Liste", das erscheint mir aber irgendwie etwas am Problem vorbei, weil man ja im Prinzip nicht immer nur zwei Dateien verarbeiten müßte.

        Und ein wenig erklärende Worte machen sich auch nie schlecht in Lösungen. :)

        - Sven Rautenberg

        --
        Die SelfHTML-Developer sagen Dankeschön für aktuell 21205,05 Euro Spendengelder!