Array of Array / Union
Hannes
- perl
Hi,
ich hab folgenes File:
NR 1;Zeitstempel A;Type A, Groesse 1
NR 2;Zeitstempel B;Type B, Groesse 2
NR 3;Zeitstempel B;Type C, Groesse 3
NR 1;Zeitstempel C;Type A, Groesse 1
NR 2;Zeitstempel A;Type A, Groesse 2
NR 3;Zeitstempel X;Type A, Groesse 3
NR 1;Zeitstempel B;Type A, Groesse 4
NR 2;Zeitstempel A;Type B, Groesse 1
...
Nun muss ich es irgendwie hinbekommen, das ich doppelte Einträge rausfiltere.
Und zwar wenn NR und Type identisch sind, dann muss die Grösse verglichen werden und es soll dann die "doppelte" Zeile mit der kleineren Grösse rausfliegen.
Ich hoffe das ist soweit verständlich?!
Meine Idee war ein AoA, also hab ich mal so angefangen:
while (<>)
{
chomp;
push @AoA, [ split(/;/,$_) ];
}
for my $i ( 0 .. $#AoA )
{
for my $j ($i .. $#AoA )
{
if ($i == $j) {next;}
if ($AoA[$i][0] eq $AoA[$j][0])
{
if ($AoA[$i][2] eq $AoA[$j][2])
{
if ($AoA[$i][3] eq $AoA[$j][3])
{
print "Nr i = $i / Nr j = $j - $AoA[$j][0] / $AoA[$j][2] / $AoA[$j][3] are equal\n";
#delete $AoA[$j];
#$AoA[$j][0]=undef;
push @{ $AoA_new[$i] }, $AoA[$i][0], $AoA[$i][2], $AoA[$i][3];
}
else
{
if ( $AoA[$j][3] > $AoA[$i][3])
{
$AoA[$i][3]=$AoA[$j][3];
#$AoA[$j][0]=undef;
push @{ $AoA_new[$i] }, $AoA[$i][0], $AoA[$i][2], $AoA[$i][3];
}
else
{
#$AoA[$j][0]=undef;
push @{ $AoA_new[$i] }, $AoA[$i][0], $AoA[$i][2], $AoA[$i][3];
}
print "NOT EQAL - Nr i = $i / Nr j = $j - $AoA[$j][0] / $AoA[$j][2] / $AoA[$j][3] = $AoA[$i][3] NOT equal\n";
#delete $AoA[$j];
}
}
}
}
}
Jedoch hab ich so natürlich wieder doppelte Einträge in $AoA_new, da ich ja nicht $AoA[$j] lösche bzw. wenn ich es mache mit delete, dann kommt die Fehlermeldung "Use of uninitialized value in concatenation (.) or string at".
Jemand eine Idee, wie ich das machen kann?
Danke.
ciao,
Hannes
ich hab folgenes File:
NR 1;Zeitstempel A;Type A, Groesse 1
NR 2;Zeitstempel B;Type B, Groesse 2
NR 3;Zeitstempel B;Type C, Groesse 3
NR 1;Zeitstempel C;Type A, Groesse 1
NR 2;Zeitstempel A;Type A, Groesse 2
NR 3;Zeitstempel X;Type A, Groesse 3
NR 1;Zeitstempel B;Type A, Groesse 4
NR 2;Zeitstempel A;Type B, Groesse 1
...Nun muss ich es irgendwie hinbekommen, das ich doppelte Einträge rausfiltere.
Und zwar wenn NR und Type identisch sind, dann muss die Grösse verglichen werden und es soll dann die "doppelte" Zeile mit der kleineren Grösse rausfliegen.
Ich hoffe das ist soweit verständlich?!
Erzeuge aus den Daten einen Hash
Denn Hashkeys sind einmalig in Perl
erzeuge leeren hash
iteriere über den Array
extrahiere die Tokens und speichere sie in einem Buffer
nimm die Conkatenation von NR und TYP als Key
prüfe ob der Key schon existiert.
-- wenn nein
speichere als neues Hashelement
dessen Inhalt ein 2 Element Array ist:
mit der Grösse und mit dem originalen String.
-- wenn ja
vergleiche die Grösse im Buffer mit der Grösse
die im hashelement gespeichert ist
Am Schluss konvertiere den hash wieder in einen Array.
mfg Beat
Erzeuge aus den Daten einen Hash
Denn Hashkeys sind einmalig in Perlerzeuge leeren hash
iteriere über den Array
extrahiere die Tokens und speichere sie in einem Buffer
nimm die Conkatenation von NR und TYP als Key
prüfe ob der Key schon existiert.
-- wenn nein
speichere als neues Hashelement
dessen Inhalt ein 2 Element Array ist:
mit der Grösse und mit dem originalen String.
-- wenn ja
vergleiche die Grösse im Buffer mit der Grösse
die im hashelement gespeichert istAm Schluss konvertiere den hash wieder in einen Array.
Hast du mir zu deinen Erläuterungen auch ein Codebespiel?
Wenn ich das mal sehe, dann fällt mir bestimmt leichter das zu verstehen.
Danke.
Hast du mir zu deinen Erläuterungen auch ein Codebespiel?
Wenn ich das mal sehe, dann fällt mir bestimmt leichter das zu verstehen.
Danke.
Bitte
erzeuge leeren hash
my %h
iteriere über den Array
foreach( @a ){
extrahiere die Tokens und speichere sie in einem Buffer
my @t = split /[;,]/, $_;
# trennzeichen musst du selber kontrollieren
nimm die Conkatenation von NR und TYP als Key
prüfe ob der Key schon existiert.
if( exists $h{ $t[0] . $t[2] } ){
-- wenn ja
vergleiche die Grösse im Buffer mit der Grösse
die im hashelement gespeichert ist
$h{ $t[0] . $t[2] }[0] > $t[3]
? next
: $h{ $t[0] . $t[2] }[0] = $t[3]
;
}
else{
-- wenn nein
speichere als neues Hashelement
dessen Inhalt ein 2 Element Array ist:
mit der Grösse und mit dem originalen String.
push @{ $h{ $t[0] . $t[2] } } , $t[3], $_;
}
}
Am Schluss konvertiere den hash wieder in einen Array.
@a =();
foreach( keys %h ){
push @a, $h{$_}[1];
}
mfg Beat;
Korrektur
-- wenn ja
vergleiche die Grösse im Buffer mit der Grösse
die im hashelement gespeichert ist$h{ $t[0] . $t[2] }[0] > $t[3]
? next
: $h{ $t[0] . $t[2] }[0] = $t[3]
#ersetze obige Linie mit
: (push @{ $h{ $t[0] . $t[2] } } , $t[3], $_)
;
}
mfg Beat;
--
<o(((°> ><o(((°>
<°)))o>< ><o(((°>o
Hi,
ich hab das mal so laufen lassen:
my %h;
foreach my $line (@a)
{
my @t = split (/;/,$line);
if( exists $h{ $t[0] . $t[2] } )
{
$h{ $t[0] . $t[2] }[0] > $t[3]
? next
: (push @{ $h{ $t[0] . $t[2] } } , $t[3], $_)
;
}
else{
push @{ $h{ $t[0] . $t[2] } } , $t[3], $_;
}
}
@a =();
foreach( keys %h ){
push @a, $h{$_}[1];
}
print @a;
Leider ist in @a nicht das gewünschte Ergebnis.
Use of uninitialized value in print at ./symmaskdb_new.pl line 61.
Use of uninitialized value in print at ./symmaskdb_new.pl line 61.
Use of uninitialized value in print at ./symmaskdb_new.pl line 61.
ciao,
Hannes
Hi,
sorry mein Fehler ... hatte $_ zu $line gemacht und nicht angepasst:
foreach my $line (@a)
{
my @t = split (/;/,$line);
#print @t;
if( exists $h{ $t[0] . $t[2] } )
{
if ($h{ $t[0] . $t[2] }[0] > $t[3]){next;}
else
{
push @{ $h{ $t[0] . $t[2] } } , $t[3], $line
}
}
else
{
push @{ $h{ $t[0] . $t[2] } } , $t[3], $line;
}
}
@a =();
foreach( keys %h ){
print $_;
push @a, $h{$_}[1];
}
print @a;
Bin noch am nachvollziehen, warum das so funktioniert, aber sieht schonmal gut aus. Merci.
Hi nochmal,
ich hab glaub ich hab das Prinzip verstanden - coole Lösung.
Was ich nicht verstanden habe ist, dass es mit der "wenn grösser als" nicht klappt. Es wird nämlich immer die erste gefunde Grösse gespeichert und nicht die grössere Zahl. Hat es vllt. was damit zu tun, dass es Fliesskommazahlen sind?
ciao,
Hannes
Hi nochmal,
ich hab glaub ich hab das Prinzip verstanden - coole Lösung.
Was ich nicht verstanden habe ist, dass es mit der "wenn grösser als" nicht klappt. Es wird nämlich immer die erste gefunde Grösse gespeichert und nicht die grössere Zahl. Hat es vllt. was damit zu tun, dass es Fliesskommazahlen sind?ciao,
Hannes
Ich hab es hinbekommen - Problem ist, dass push nicht überschreibt, dehsalb muss ich ...
if ($h{ $t[0] . $t[2] }[0] > $t[3]){next;}
else
{
$h{$t[0] . $t[2] }[0]=$t[3];
$h{$t[0] . $t[2] }[1]=$line;
}
... machen
Ich hab es hinbekommen - Problem ist, dass push nicht überschreibt, dehsalb muss ich ...
if ($h{ $t[0] . $t[2] }[0] > $t[3]){next;}
else
{
$h{$t[0] . $t[2] }[0]=$t[3];
$h{$t[0] . $t[2] }[1]=$line;
}
> ... machen
Tja, auch Korrekturen sollte man überdenken...
Ich habe den Code ungetestet gepostet weil ich den Kopf derzeit in 99 offenen Fenstern habe.
mfg Beat
--
><o(((°> ><o(((°>
<°)))o>< ><o(((°>o