Martin König: Sortierproblem

Ich habe in einer Datei test.txt zeilenweise Daten liegen. Diese sind so aufgebaut:

wort1,5,5,3,5,5,5
wort2,5,5,1,5,5,5
wort3,5,5,2,5,5,5

Wenn ich diese per Dateihandle übergebe habe ich ein array @daten, in denen jetzt diese Daten liegen. Nun möchte ich die einzelnen $daten[0], $daten[1], $daten[2] sortieren. Und zwar nach dem jeweiligen 4. Element, so daß es hinterher so aussieht:

wort2,5,5,1,5,5,5  $daten[0]  (vorher $daten[1])
wort3,5,5,2,5,5,5  $daten[1]  (vorher $daten[2])
wort1,5,5,3,5,5,5  $daten[2]  (vorher $daten[0])

Entweder ich seh den Baum vor lauter Wald nicht oder ich bin blöd!

Danke für die Hilfe!

  1. Wenn ich diese per Dateihandle übergebe habe ich ein array @daten, in denen jetzt diese Daten liegen. Nun möchte ich die einzelnen $daten[0], $daten[1], $daten[2] sortieren. Und zwar nach dem jeweiligen 4. Element, so daß es hinterher so aussieht:
    wort2,5,5,1,5,5,5  $daten[0]  (vorher $daten[1])
    wort3,5,5,2,5,5,5  $daten[1]  (vorher $daten[2])
    wort1,5,5,3,5,5,5  $daten[2]  (vorher $daten[0])

    Normales Sortiern kannst Du?

    Dann ergänze bei sort eine Sortiermethode { x(a) <=> x(b) } und schreibe Dir die Funktion x dazu: Parameterwert mit split() an den Kommata zerlegen und nur die 4. Komponente zurückliefern.

    Je nachdem, ob diese Werte dann numerisch oder stringweise sortiert werden soll, käme statt "<=>" auch "cmp" in Frage.

    1. @daten = sort {x($a) <=> x($b)} @daten;

      sub x
      {
           ($nicht1,$nicht2,$nicht3,$wichtig,..) = split(/,/,$daten[ ??? ]);
           $a = $wichtig;
      }

      Versteh ich nicht so recht!?   ;-/    *grübel

      1. @daten = sort {x($a) <=> x($b)} @daten;

        sub x
        {
             ($nicht1,$nicht2,$nicht3,$wichtig,..) = split(/,/,$daten[ ??? ]);
             $a = $wichtig;
        }

        Versteh ich nicht so recht!?   ;-/    *grübel

        Dabei bist Du gar nicht weit weg. Nur zwei Schritte:

        1. Die Funktion wird von sort() mit einem (skalaren) Parameter aufgerufen. Auf den mußt Du zugreifen, nicht auf @daten.

        2. Und ihr Ergebnis muß sie nicht an $a zuweisen (eine solche Variable existiert m. E. gar nicht - in welchem scope auch? Das ist nur eine symbolische Notation), sondern mit "return $wichtig;" dem Aufrufer zurückliefern. Denn die sort()-Funktion will das Ergebnis Deiner Funktion ja dann zum Vergleichen verwenden, während sie sortiert.

        Und - tut es?

        1. Hi!

          @daten = sort {x($a) <=> x($b)} @daten;

          sub x
          {
               ($nicht1,$nicht2,$nicht3,$wichtig,..) = split(/,/,$daten[ ??? ]);
               $a = $wichtig;
          }

          1. Die Funktion wird von sort() mit einem (skalaren) Parameter aufgerufen. Auf den mußt Du zugreifen, nicht auf @daten.

          Sagen wir's doch einfach auf Deutsch:
          sub x {
              my $line = shift;
              my $wichtig;

          (undef, undef, undef, $wichtig, undef) = split(/,/, $line);
              return $wichtig;
          }

          1. Und ihr Ergebnis muß sie nicht an $a zuweisen (eine solche Variable existiert m. E. gar nicht - in welchem scope auch? Das ist nur eine symbolische Notation),

          Doch doch, die existiert tatsaechlich. $a und $b sind globale Variablen im aktuellen package. Die Perl-Erfinder haben diesen Weg aus Geschwindigkeitsgruenden gewaehlt. See also perldoc->perlfunc->sort.

          Um noch etwas mehr Geschwindigkeit rauszukitzeln, kann man vielleicht die sub x ganz weglassen und stattdessen einfach
            @daten = sort { (split(/,/, $a))[3] <=> (split(/,/, $b))[3] } @daten;
          schreiben. Falls die einzelnen Felder in jeder Zeile dieselbe Laenge haben, kann man statt split() auch substr() verwenden, was wahrscheinlich noch schneller wird.

          So long

          1. Sagen wir's doch einfach auf Deutsch:

            Ich weiß schon, wieso ich keine exakte Syntax poste ... (nicht nur, weil ich ohne Compiler hilflos bin - bei Fragestellung und Reaktion zeigt Martin immerhin gute Ansätze, auf dieser Ebene macht mir das Antworten Spaß ...)

            @daten = sort { (split(/,/, $a))[3] <=> (split(/,/, $b))[3] } @daten;

            Yep - und genau das ist die Methode, mit denen man  Einsteigern von vornherein beibringt, Code zu schreiben, den niemand außer ihnen lesen kann.
            Jetzt laß' ihn doch erst mal modulares Programmieren üben - "rumsauen" lernt er noch früh genug ... ;-)

            1. Diese verschachteln war mir nicht ganz klar, jetzt funktionierts.

              Vielen Dank!

              Bis zum nächsten Problem ;-)