$xNeTworKx: Hashelement ignorieren, wenn Schlüssel und Wert gleich ?

Guten Morgen,
Folgendes Problem: In sehr vielen Dateien habe ich Usernamen und deren IP Adressen gespeichert. Jetzt will ich von jedem User die IP bzw IP's auflisten lassen.
Ich hätte es aber gerne so, dass wenn ein User schon mal aufgelistet worden ist, er nur mehr nochmal aufgelistet wird, wenn einen weitere IP von ihm gefunden wird bzw dass nur die neue IP neben der alten neben seinem Namen erscheint. Dazu müsste ich wissen, ob bei gleichen Hashschlüsseln auch gleiche Werte exisitieren, aber wie kann man das am Besten lösen ? Gleiche Hash Schlüssel findest man mit exists, das ist klar, aber wie kann ich es effizient lösen, dass nur die Schlüssel gefunden werden, die auch gleiche Wert haben ?
Mein Code sieht zur Zeit so aus (Natürlich werden jetzt noch gleiche Hashschlüssel überschrieben)

opendir(DIR,'messages') or die "Cant open postings : $! \n";
    while (defined($_ = readdir(DIR)))   {
        if ($_ =~ /^\d+?.cgi$/)   {
        open(FILE,"messages/$_") or die "Cant open $_ : $!\n";
        local $/;
        my $input = <FILE>;
        close FILE;
            while ($input =~ /<posting=\d+?>(.+?)</posting>/sg)   {
            my $i = 0;
            my $data = $1;
            my $ip = $1 if $data =~ /<ip>(.+?)</ip>/;
            my $name = $1 if $data =~ /<name>(.+?)</name>/;
            $namenshash{$name} = $ip;
            }
         }
    }
    closedir DIR;

$xNeTworKx.

  1. Guten Morgen,
    Folgendes Problem: In sehr vielen Dateien habe ich Usernamen und deren IP Adressen gespeichert. Jetzt will ich von jedem User die IP bzw IP's auflisten lassen.
    Ich hätte es aber gerne so, dass wenn ein User schon mal aufgelistet worden ist, er nur mehr nochmal aufgelistet wird, wenn einen weitere IP von ihm gefunden wird bzw dass nur die neue IP neben der alten neben seinem Namen erscheint. Dazu müsste ich wissen, ob bei gleichen Hashschlüsseln auch gleiche Werte exisitieren, aber wie kann man das am Besten lösen ? Gleiche Hash Schlüssel findest man mit exists, das ist klar, aber wie kann ich es effizient lösen, dass nur die Schlüssel gefunden werden, die auch gleiche Wert haben ?
    Mein Code sieht zur Zeit so aus (Natürlich werden jetzt noch gleiche Hashschlüssel überschrieben)

    opendir(DIR,'messages') or die "Cant open postings : $! \n";
        while (defined($_ = readdir(DIR)))   {
            if ($_ =~ /^\d+?.cgi$/)   {
            open(FILE,"messages/$_") or die "Cant open $_ : $!\n";
            local $/;
            my $input = <FILE>;
            close FILE;
                while ($input =~ /<posting=\d+?>(.+?)</posting>/sg)   {
                my $i = 0;
                my $data = $1;
                my $ip = $1 if $data =~ /<ip>(.+?)</ip>/;
                my $name = $1 if $data =~ /<name>(.+?)</name>/;
                $namenshash{$name} = $ip;
                }
             }
        }
        closedir DIR;

    $xNeTworKx.

    Hallo

    so würde es gehen:

    open(DATEI, 't.txt') || die "ging nicht";
    while(<DATEI>){
      chomp($_);
      ($name,$nummer) = split(/:/,$_);
      if(exists $hash{$name}){
         $hash{$name} .= ":".$nummer;
      }
      else{
        $hash{$name} = $nummer;
      }
    }
    foreach $el (keys %hash){
      %tmp = ();
      @a = split(/:/,$hash{$el});
      foreach $a(@a){
        $tmp{$a} = 1;
      }
      $hash{$el} =join(":", keys (%tmp)) ;
    }

    foreach $b (keys %hash){
      print "$b $hash{$b} \n";
    }

    In diesem Fall steht in der t.txt z.b.:
    xNeTworKx:333
    perlanfaenger:123
    xNeTworKx:999

    es geht auch noch schöner mit komplexen datenstrukturen,
    die habe ich aber noch nicht gelernt :)

    gruss
    perlanfänger

    1. Hi,

      open(DATEI, 't.txt') || die "ging nicht";

      open(DATEI, 't.txt') or die "ging nicht weil : $!\n";

      while(<DATEI>){
        chomp($_);
        ($name,$nummer) = split(/:/,$_);
        if(exists $hash{$name}){
           $hash{$name} .= ":".$nummer;
        }
        else{
          $hash{$name} = $nummer;
        }
      }

      Das ist ein Fehler. So würde jeder Key maximal 2 Mal exisitieren, und die weiteren Überschrieben werden, weil du abfragst, ob der Hash Schlüssel XY schon exisitert -> Wenn nicht Hash Schlüssel ist XZ, aber was ist wenn XZ schon exisitert, würde XZ überschrieben werden.
      Die Lösung würde vereinfacht lauten (Wenn $name jetzt eine Zahl wäre):

      while (exists $namenshash{$name})   {
      $name++;
      }
      $namenshash{$name} = $ip;

      foreach $el (keys %hash){

      foreach (sort {$a cmp $b} keys %hash)  {

      Die Zuordnung zu einer Variable $el ist nicht nötig.
      Du kannst die Schlüssel auch mit $_ ausgeben, und die Werte mit $hash{$_}

      %tmp = ();
        @a = split(/:/,$hash{$el});
        foreach $a(@a){
          $tmp{$a} = 1;
        }
        $hash{$el} =join(":", keys (%tmp)) ;
      }

      foreach $b (keys %hash){
        print "$b $hash{$b} \n";
      }

      In diesem Fall steht in der t.txt z.b.:
      xNeTworKx:333
      perlanfaenger:123
      xNeTworKx:999

      es geht auch noch schöner mit komplexen datenstrukturen,
      die habe ich aber noch nicht gelernt :)

      Hi, genau die meine ich aber :), weil es hier um eine große Datenmenge geht, und die will ich nun mal nicht herum joinen und splitten.

      $xNeTworKx.

      1. Hi,

        open(DATEI, 't.txt') || die "ging nicht";

        open(DATEI, 't.txt') or die "ging nicht weil : $!\n";

        while(<DATEI>){
          chomp($_);
          ($name,$nummer) = split(/:/,$_);
          if(exists $hash{$name}){
             $hash{$name} .= ":".$nummer;
          }
          else{
            $hash{$name} = $nummer;
          }
        }

        Das ist ein Fehler. So würde jeder Key maximal 2 Mal exisitieren,

        und die weiteren Überschrieben werden, weil du abfragst, ob der Hash Schlüssel XY schon exisitert -> Wenn nicht Hash Schlüssel ist XZ, aber was ist wenn XZ schon exisitert, würde XZ überschrieben werden.

        Die Lösung würde vereinfacht lauten (Wenn $name jetzt eine Zahl wäre):

        while (exists $namenshash{$name})   {
        $name++;
        }
        $namenshash{$name} = $ip;

        nö, das funktioniert so:
        $hash{$name} .= ":".$nummer;
                     ^^^^

        foreach $el (keys %hash){

        foreach (sort {$a cmp $b} keys %hash)  {

        Die Zuordnung zu einer Variable $el ist nicht nötig.
        Du kannst die Schlüssel auch mit $_ ausgeben, und die Werte mit $hash{$_}

        %tmp = ();
          @a = split(/:/,$hash{$el});
          foreach $a(@a){
            $tmp{$a} = 1;
          }
          $hash{$el} =join(":", keys (%tmp)) ;
        }

        foreach $b (keys %hash){
          print "$b $hash{$b} \n";
        }

        In diesem Fall steht in der t.txt z.b.:
        xNeTworKx:333
        perlanfaenger:123
        xNeTworKx:999

        es geht auch noch schöner mit komplexen datenstrukturen,
        die habe ich aber noch nicht gelernt :)

        Hi, genau die meine ich aber :), weil es hier um eine große Datenmenge geht, und die will ich nun mal nicht herum joinen und splitten.

        ich werds mal versuchen...

        gruss

        1. Hi,

          Die Lösung würde vereinfacht lauten (Wenn $name jetzt eine Zahl wäre):

          while (exists $namenshash{$name})   {
          $name++;
          }
          $namenshash{$name} = $ip;

          nö, das funktioniert so:
          $hash{$name} .= ":".$nummer;

          ^^^^

          Ich meine, wenn $name eine Zahl wäre. Natürlich kann man jetzt das Ganze auf seine Verhältnisse anpassen.
          Bei deiner Lösung würden die Werte um .= ":".$nummer; drangestückelt werden, ich brauche aber die Schlüssel. Wenn ich es an den Namen dranstückeln würde, würde die Ausgabe außerdem so lauten :

          $xNeTworKx0
          $xNeTworKx01
          $xNeTworKx012

          $xNeTworKx.

          1. Hi nochmal,

            Wenn ich es an den Namen dranstückeln würde, würde die Ausgabe außerdem so lauten :

            $xNeTworKx0
            $xNeTworKx01
            $xNeTworKx012

            Das ist natürlich eoin Schwachsinn. Da hab ich mich jetzt selbst verwirrt.

            $xNeTworKx.

          2. Hi,

            so jetzt mal mit komplexen datenstrukturen:

            open(DATEI, 't.txt') || die "ging nicht";

            while(<DATEI>){
              chomp($_);
              ($name,$nummer) = split(/:/,$_);
              $hash{$name}{$nummer}++;
            }

            foreach $name (keys %hash){
              print "$name: ";
              foreach $keys (keys %{$hash{$name}}){
                print "IP: $keys kam $hash{$name}{$keys} vor";
              }
              print "\n";
            }

            ja ich weiss, es gibt $_ ... kann mich aber noch nicht so recht dran
            gewöhnen

            gruss
            perl_anfänger

  2. Moin!

    Folgendes Problem: In sehr vielen Dateien habe ich Usernamen und deren IP Adressen gespeichert. Jetzt will ich von jedem User die IP bzw IP's auflisten lassen.

    Mal sehen, ob ich dich verstanden habe:

    Du hast eine lange Liste von Zuordnungen:
    user1 = ip1
    user2 = ip2
    user1 = ip3

    Und du hättest das gerne komprimiert:
    user1 = ip1, ip3
    user2 = ip2

    Dann würde ich vorschlagen, mit doppelten Hashes zu arbeiten:

    Erste Ebene: Username.
    Zweite Ebene: IP-Adresse.
    Inhalt der zweiten Ebene: irgendein Wert, beispielsweise ein Conuter, der die Zahl der Vorkommen listet.

    Also sowas:
    $userhash{'user1'}{'ip1'}
    $userhash{'user2'}{'ip2'}
    $userhash{'user1'}{'ip3'}

    Keine Garantie, dass das mit den Hashes in Hashes in Perl genau _so_ funktioniert - ich mach zuwenig in Perl.

    Die Ausgabe wäre dann recht simpel: Du gehst die oberste Ebene mit allen Usernamen durch und in einer Schleife dann alle IP-Adressen dieses Users. Wahlweise kannst du dann natürlich auch noch den Counter-Wert (wenn du denn die Vorkommen zählen willst) ausgeben.

    - Sven Rautenberg

    --
    Diese Signatur gilt nur am Freitag.
    1. Hi,
      ok danke, werde es so versuchen.

      $xNeTworKx