Hashelement ignorieren, wenn Schlüssel und Wert gleich ?
$xNeTworKx
- perl
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.
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
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:999es 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.
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:999es 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
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.
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.
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
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
Hi,
ok danke, werde es so versuchen.
$xNeTworKx