$xNeTworKx: ?....? bei Hash, wie push bei Liste ?

Hi,
ich habe mich gefragt, ob es möglich ist, in einer Schleife einen Hash immer mit 2 neuen Werten zu füttern ?
Ich könnte natürlich hergehen, und zuerst mal die 2 Elemente, pro Schleifendurchlauf in eine Liste "pushen" und die Liste ganz normal in einen Hash rüberschieben, aber so verdopple ich ja quasi gleich den Speicherbedarf. Gibt es nicht eine elegantere Lösung ?

$xNeTworKx.

  1. Halihallo

    ich habe mich gefragt, ob es möglich ist, in einer Schleife einen Hash immer mit 2 neuen Werten zu füttern ?
    Ich könnte natürlich hergehen, und zuerst mal die 2 Elemente, pro Schleifendurchlauf in eine Liste "pushen" und die Liste ganz normal in einen Hash rüberschieben, aber so verdopple ich ja quasi gleich den Speicherbedarf. Gibt es nicht eine elegantere Lösung ?

    Ich versteh dein Vorgehen nicht, kannst du vielleicht ein Beispiel schreiben?

    Was willst du erreichen?

    Was ist gemeint mit "einen Hash mit immer 2 neuen Werten zu füttern"?

    for (...) {
       $hash{$first} = $second;
       # oder
       $hash{$bla} = [$first, $second];
       # oder
       %hash = @neue_elemente;
    }

    ??? - Was soll denn innerhalb der Schleife rauskommen?

    Viele Grüsse

    Philipp

    1. Hi,

      Was ist gemeint mit "einen Hash mit immer 2 neuen Werten zu füttern"?

      Ich habe einen Dateinamen der sich so zusammensetzt : Unixzeit + .cgi (zB 242353535.cgi)
      In der Datei steht wieder eine Zahl, die auch eine Unixzeit ist, und ich will die Dateien nach der inneren Unixzeit sortieren, weil ich dann die neuesten 20 Dateien brauche. (Die Dateien, die die 20 höchsten Unixzeiten in der Datei drin stehen haben).

      opendir(DIR,'messages') or die "Cant open postings : $! \nPlease send a mail to $mailadmin to report this error\n";
         while (defined($_ = readdir(DIR)))   {
              if ($_ =~ /^\d+?.cgi$/)   {
              my $headdata = '';
              open(FILE,"messages/$_") or die "Cant open $_ : $! \nPlease send a mail to $mailadmin to report this error\n";
              for (my $i = 0; $i < 1; $i++)    {   #die erste Zeile einlesen
              $headdata = <FILE>;
               my $unixzeit = $1 if $headdata =~ /<unix>(\d+?)</unix>/;
               push @postingliste ,$unixzeit, $_;
               }
               close FILE;
          }
      }
      closedir DIR;

      Jetzt müsste ich %postinghash = @postingliste;  angeben, damit ich die dateiinternen Unixwerte sortieren kann, und die Datei an sich als Wert habe, weil ich diese 20 neuesten Dateien dann öffnen muss.
      Nur will ich doch nicht den Speicherberech verdoppeln, also ich will nicht %postinghash = @postingliste;  angeben müssen, sondern gleich $unixzeit und $_ und den Hash einlesen ?

      $xNeTworKx.

      1. Halihallo

        for (my $i = 0; $i < 1; $i++)    {   #die erste Zeile einlesen
        $headdata = <FILE>;

        Na, was soll'n diese for-Schleife? - Die erste Zeile einer Datei liest man immer noch über $headdata = <FILE> ein, ohne die for-Schleife...

        my $unixzeit = $1 if $headdata =~ /<unix>(\d+?)</unix>/;
                 push @postingliste ,$unixzeit, $_;

        $postinghash{$unixzeit} = $_;

        my @sort = sort { $a <=> $b } keys %postinghash;

        my @topzwens = splice(@sort, 0, 19);

        foreach my $unixtime (@topzwens) {
           my $related_file = $postinghash{$unixtime};
        }

        ach ja, das setzt voraus, dass jede mögliche unixtime wirklich nur einmal vorkommt, sonst gehen gleiche unixtimes verloren. Falls du dies nicht ausschliessen kannst, musst du jedem Hash-Key ein anonymes Array zuweisen:

        unless (ref($postinghash{$unixzeit}) eq 'ARRAY') {
           $postinghash{$unixzeit} = [];
        }
        push @{$postinghash{$unixzeit}}, $_;

        ...

        Viele Grüsse

        Philipp

        1. Hallo,

          $postinghash{$unixzeit} = $_;

          my @sort = sort { $a <=> $b } keys %postinghash;

          my @topzwens = splice(@sort, 0, 19);

          foreach my $unixtime (@topzwens) {
             my $related_file = $postinghash{$unixtime};
          }

          Das verstehe ich alles, danke..

          ach ja, das setzt voraus, dass jede mögliche unixtime wirklich nur einmal vorkommt, sonst gehen gleiche unixtimes verloren.

          unless (ref($postinghash{$unixzeit}) eq 'ARRAY') {
             $postinghash{$unixzeit} = [];
          }
          push @{$postinghash{$unixzeit}}, $_;

          Aber das irgendwie nicht so ganz :)

          $xNeTworKx.

          1. Halihallo

            ach ja, das setzt voraus, dass jede mögliche unixtime wirklich nur einmal vorkommt, sonst gehen gleiche unixtimes verloren.

            unless (ref($postinghash{$unixzeit}) eq 'ARRAY') {
               $postinghash{$unixzeit} = [];
            }
            push @{$postinghash{$unixzeit}}, $_;

            Aber das irgendwie nicht so ganz :)

            also, wenn du zweimal die selbe Zeit (in <unix>...</unix>) hast und du einen normalen, scalaren Wert in den Hash schreibst, dann überschreibst du ja immer den letzten Wert. Deshalb musst du auf ein referenziertes Array ausweichen, um auch bei derselben Unixzeit zwei Dateien speichern zu können (eben diezwei Dateien, die genau dieselbe Unixzeit enthalten). Enthält eine Datei dieselbe Unixtime, dann wird der Dateiname einfach an das Array gepusht. Aber bevor gepusht werden kann, muss der Hash-Value eine gültige Arrayreferenz enthalten, dies kann man über ref($hash{$key}) eq 'ARRAY' testen. Falls es eben noch kein referenziertes Array ist, machen wir eben eines mit $postinghash{$unixtime} = []. Nun ist alles bereit, um neue Werte ans Ende zu pushen. Im normalfall wirst du jedoch nur immer ein anonymes Array mit einem Element haben, aber es ist eben auch möglich, dass es mehrere Elemente hat.

            über @{$postinghash{$unixtime}} dereferenzierst du das anonyme Array und kannst über die Array-Befehle darauf zugreifen.

            $ref_to_array = [ 'bla', 'bla2' ];
            $ref_to_array = @norm_array;

            @to_norm_array = @{$ref_to_array};

            push @{$ref_to_array}, 'test';  # bezogen auf das erste Beispiel...

            gibt's das ['bla', 'bla2', 'test']

            war's das - oder is' noch was offen?

            Viele Grüsse

            Philipp

            1. Hi,

              über @{$postinghash{$unixtime}} dereferenzierst du das anonyme Array und kannst über die Array-Befehle darauf zugreifen.

              $ref_to_array = [ 'bla', 'bla2' ];
              $ref_to_array = @norm_array;

              @to_norm_array = @{$ref_to_array};

              push @{$ref_to_array}, 'test';  # bezogen auf das erste Beispiel...

              gibt's das ['bla', 'bla2', 'test']

              Naja, mit den seltsamen Schreibweisen wie @{ komme ich irgendwie noch nicht ganz klar =), aber ich muss mir das noch genauer ansehen, danke.

              $xNeTworKx.

              1. Halihallo $xNeTworKx

                Naja, mit den seltsamen Schreibweisen wie @{ komme ich irgendwie noch nicht ganz klar =), aber ich muss mir das noch genauer ansehen, danke.

                Naja, ich kann ja mal versuchen mit einigen Sätzen helfen:

                Ein Array oder Hash ist eine Ansammlung von einzelnen Skalaren (eg. Zahl, String, ...), wohingegen eine Array/Hash-Referenz ein Skalar ist, der die Adresse zum Hash/Array speichert. Der eigentliche Hash/Array "Inhalt" ist an der genannten Adresse zu finden, jedoch nicht in der Referenz per se (das ist ein Pointer/Zeiger auf den eigentlichen Inhalt).
                Wenn du nun eine Arrayreferenz bildest...

                $array_ref = @norm_array;

                ... dann enthält $array_ref die Adresse ( 'ARRAY(0xac98f2)' ) auf das Array (...).
                Mit $array_ref kannst du eigentlich nicht sehr viel anfangen, da es lediglich eine Adresse enthält, um auf das Array selber zuzugreifen musst du die Referenz dereferenzieren:

                @{$array_ref}

                dann kannst du mit diesem Array arbeiten, z. B.

                push @{$array_ref}, 'value';

                das selbe geht mit Hashes, dort ändert einfach das @{ auf %{.

                Naja, irgendwie führt das doch etwas sehr weit bzw. gibt missverständnisse, wenn man das in so kurzen Zügen erklären möchte, deshalb:

                perldoc perldata
                perldoc perlreftut
                perldoc perllol
                perldoc perlref

                ... sind da schon etwas ausführlicher.

                Viele Grüsse und Spass bei der Lektüre ;-)

                Philipp

                1. Hi,
                  hab bis jetzt nur mit Skalar Referenzen gearbeitet, deswegen sind mir noch andere Schreibweisen nicht so vertraut. Wenn ich aber zB sowas sehe @elemente = @{ $zahlen[1] }[2..5]; bin ich nicht mehr so ganz sicher, was das jetzt eigentlich heißen soll (Wenn ichs nicht zufällig aus dem Buch herausgelesen hätte) =)

                  $xNeTworKx.

                  1. Halihallo $xNeTworKx

                    hab bis jetzt nur mit Skalar Referenzen gearbeitet, deswegen sind mir noch andere Schreibweisen nicht so vertraut. Wenn ich aber zB sowas sehe @elemente = @{ $zahlen[1] }[2..5]; bin ich nicht mehr so ganz sicher, was das jetzt eigentlich heißen soll (Wenn ichs nicht zufällig aus dem Buch herausgelesen hätte) =)

                    Auch wenn du dies aus dem Buch gelesen hast, wage ich nochmal einen Einstieg und erkläre nochmals in kurzen Zügen:

                    $zahlen[1] ist ein Skalar und enthält eine Adresse auf ein Array. Da du nun in @elemente die Elemente 2-5 des Arrays speichern möchtest, bringt dir die Adresse alleine nix. Du musst das Array mit @{...} dereferenzieren, erst dann kannst du mit [2..5] einen splice des Arrays machen (was sollte denn einen Splice auf eine Adresse bedeuten? - Nix! => deshalb dereferenzieren, dann kriegst du aus der Adresse wieder ein Array). Aber keine Sorge, wenn ich sowas sehe, muss ich auch erst zweimal nachsehen, bis ich den Sinn verstehe :-)

                    Na, jetzt lass ich dich in Ruhe mit dem Dereferenzieren. Falls du noch Fragen hast, kennst du ja die URL des Forums :-)

                    Viele Grüsse

                    Philipp