Hannes: Array of Array / Union

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

  1. 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

    --
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    1. 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.

      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.

      1. 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;

        --
        ><o(((°>           ><o(((°>
           <°)))o><                     ><o(((°>o
        1. 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

          1. 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

            1. 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.

              1. 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

                1. 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

                  1. 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