siggi: Arrays bearbeiten

Hallo Leute,
ich grübel hier über einem kleinen Problem, welches bestimmt nicht allzu schwer ist zu lösen, nur leider komm ich nicht drauf.

Ich habe 2 Arrays, jeweils gefüllt mit Namen und Werten ...

Bsp Array 1:

name1 ... 20
name2 ... 30
...

usw (Array 2 ähnlich, aber mit anderen Werten, aufgebaut)

Jetzt habe ich noch ein 3. Array gefüllt mit Namen, welche ich aus den ersten 2 Arrays entfernen will.

Habe den Teil bis jetzt in etwa so gelöst.

foreach my $name (@array3){
        foreach my $i @array1{
                if($i !~ m/^$typ/){
                        push(@namen1_neu,$i);
                }
        }
        foreach my $i @array2{
                if($i !~ m/^$typ/){
                        push(@namen2_neu,$i);
                }
        }
}

Nur leider entfernt er immer nur den ersten Namen, welcher im array3 angegeben ist. Wie könnte mein Problem zu lösen sein? Hat jemand einen Tipp für mich, oder muß ich das mit Rekursion lösen?

mfg

  1. Nur leider entfernt er immer nur den ersten Namen, welcher im array3 angegeben ist. Wie könnte mein Problem zu lösen sein? Hat jemand einen Tipp für mich, oder muß ich das mit Rekursion lösen?

    Ich verstehe dein Problem nicht, könntest du ein lauffähigen Code mit Beispieldaten zeigen?

    Struppi.

  2. Hallo,

    Jetzt habe ich noch ein 3. Array gefüllt mit Namen, welche ich aus den ersten 2 Arrays entfernen will.

    Am Besten, Du map'st die ersten beiden arrays auf jeweils einen hash, gehst dann mit _einer_ Schleife durch das dritte array mit den Namen und bedienst Dich der Funktion delete() um die Namen aus den ersten beiden arrays (hash) zu löschen.

    Zum Schluss map'st Du die ersten beiden hashes wieder auf arrays (falls  notwendig). Allerdings geht dabei die Sortierung flöten, ggf. musst Du halt neu sortieren.

    Viele Grüße,
    Hotte

  3. Ich habe 2 Arrays, jeweils gefüllt mit Namen und Werten ...

    Öhm, Du hast Arrays? Das klingt aber irgendwie nach Hashes.

    Jetzt habe ich noch ein 3. Array gefüllt mit Namen, welche ich aus den ersten 2 Arrays entfernen will.

    Das habe ich glaube ich verstanden.

    Habe den Teil bis jetzt in etwa so gelöst.

    Dein Code läuft so nicht, sondern bricht mit einer Fehlermeldung ab. Der Grund:

    foreach my $i @array1{
            foreach my $i @array2{

    Da fehlen Klammern um @array1 bzw. @array2. Ergänze diese und je nach Ausgangsdaten funktioniert Dein Code eigentlich wie gewünscht.

    Wie könnte mein Problem zu lösen sein? Hat jemand einen Tipp für mich, oder muß ich das mit Rekursion lösen?

    Mit Rekursion hat das nichts zu tun. Eventuell hilft Dir perlfaq4 weiter. Ansonsten: Welche Ausgangsdaten verwendest Du, was soll das Ergebnis sein und welchen Zweck verfolgst Du damit?

    Siechfred

    --
    Coping With Scoping (Deutsche Übersetzung)
    Als Moderator habe ich keinerlei Humor, von dem ich wüsste.
  4. Hi

    Habe den Teil bis jetzt in etwa so gelöst.

    das der code nie gelaufen ist hat uns ja schon siechfred gezeigt...

    foreach my $name (@array3){
            foreach my $i @array1{
                    if($i !~ m/^$typ/){
                            push(@namen1_neu,$i);
                    }
            }
            foreach my $i @array2{
                    if($i !~ m/^$typ/){
                            push(@namen2_neu,$i);
                    }
            }
    }

    aber wieso $typ steht wo $name stehen sollte ist unklar.
    Auch prüfst du nicht auf Identität sondern auf enthaltensein.

    Kurt

    1.   
      @exclude=(6..10);  
      @array1=(1..10);  
      @array2=(10,5,5,10);  
        
      $,="\t";$\="\n";  
      print @array1;  
      print @array2;  
      #: 1 2 3 4 5 6 7 8 9 10  
      #: 10 5 5 10  
        
        
      foreach my $exclude (@exclude){  
       @array1=grep {! /^$exclude$/} @array1;  
       @array2=grep {! /^$exclude$/} @array2;  
       }  
        
        
      print @array1;  
      print @array2;  
      #: 1 2 3 4 5  
      #: 5 5  
      
      

      wenns auf die Performance ankommt könnte man sich überlegen einen einzigen RegEx ausdruck aus @exclude zu basteln, sowas wie join("|",@exclude)

      danke für die Aufgabe am morgen... :)

      1. Und ... wer keine RegExes mag kommt mit folgender Form besser zurecht:

          
        
        > @exclude=(6..10);  
        > @array1=(1..10);  
        > @array2=(10,5,5,10);  
        >   
        > $,="\t";$\="\n";  
        > print @array1;  
        > print @array2;  
        > #: 1 2 3 4 5 6 7 8 9 10  
        > #: 10 5 5 10  
        >   
        >   
        > foreach my $exclude (@exclude){  
        
         @array1=grep {$_ ne $exclude} @array1;  
         @array2=grep {$_ ne $exclude} @array2;  
        
        >  }  
        >   
        >   
        > print @array1;  
        > print @array2;  
        > #: 1 2 3 4 5  
        > #: 5 5  
        
        

        Kurt

        1. Und ... wer keine RegExes mag kommt mit folgender Form besser zurecht:

          Und wer's performant mag, nimmt einen Hash-Slice:

          my @array1 = (1..10);  
          my %wanted;  
          @wanted{(6..10} = ();  
          @array1 = grep { exists $wanted{$_} } @array1;
          

          Diese Variante ist bei mir mehr als 7mal so schnell wie die foreach-Variante. Zum Selbertesten:

          use strict;  
          use Benchmark;  
            
          my @array1 = (1..10);  
            
          Benchmark::cmpthese(-1, {  
              'foreach_grep'  =>  sub { my @wanted = (6..10);;  
                                        foreach my $exclude (@wanted) {  
                                          @array1 = grep { $_ ne $exclude } @array1;  
                                        }  
                                      },  
              'slice_grep'    =>  sub { my %wanted;  
                                        @wanted{(6..10)} = ();  
                                        @array1 = grep { exists $wanted{$_} } @array1;  
                                      },  
          });
          

          Ergibt bei mir:

                          Rate   foreach_grep   slice_grep  
          foreach_grep  6775/s             --         -89%  
          slice_grep   58964/s           770%           --
          

          Siechfred

          --
          Coping With Scoping (Deutsche Übersetzung)
          Als Moderator habe ich keinerlei Humor, von dem ich wüsste.
          1. Und wer's performant mag, nimmt einen Hash-Slice:

            Und ehe es ein anderer merkt (um mit ne zu vergleichen, muss exists auch negiert werden):

            Benchmark::cmpthese(-1, {  
                'foreach_grep'  =>  sub { my @wanted = (6..10);;  
                                          foreach my $exclude (@wanted) {  
                                            @array1 = grep { $_ ne $exclude } @array1;  
                                          }  
                                        },  
                'slice_grep'    =>  sub { my %wanted;  
                                          @wanted{(6..10)} = ();  
                                          @array1 = grep { !exists $wanted{$_} } @array1;  
                                        },  
            });
            

            Ergibt dann einen Geschwindigkeitsvorteil von ca. 2,5 zugunsten des Slices.

            Siechfred

            --
            Coping With Scoping (Deutsche Übersetzung)
            Als Moderator habe ich keinerlei Humor, von dem ich wüsste.
            1. Hi

              Ergibt dann einen Geschwindigkeitsvorteil von ca. 2,5 zugunsten des Slices.

              chic..echt chic! Endlich mal eine parktische Übung mit hashslices (und wahrscheinlich der Hauptanwendungsfall :)

              Die Beschleunigung ist sogar höher als du denkst, weil Benchmark die prozentuale Differenz anzeigt, also +770%  heißt 8,7 mal schneller.

              hab auch mal die Variante ausprobiert, wo alle excludes in einer großen RegEx drin sind, die war nur noch halb so schnell wie der Array slice.

              'regex_grep'  =>  sub { my @wanted = (6..10);
                                         my $regex=join("|",@wanted);
                                         @array1 = grep { ! /^($regex)$/ }                @array1;
                                          },

              Allerdings wenn mans viele Arrays filtern möchte, könnte man die RegEx vorkompilieren lassen...

              Ne andere Variante ohne grep direkt mit Hashslice hätte den Nachteil dass identische Arrayinhalte wegfielen...

              @exclude=(6..10);
               @array1=(1..10);
               @array2=(10,5,5,10);

              $,="\t";$="\n";

              @hash1{@array1}=();
              @hash2{@array2}=();
              print keys %hash1;
              print keys %hash2;

              delete @hash1{@exclude};
              delete @hash2{@exclude};

              print keys %hash1;
              print keys %hash2; # hier kommt nur 5 raus

              Aber den Sigil @ bei den Hashslices kann ich mir gerade nicht intuitiv erklären oder leicht merken... hm oder doch muss mal recherchieren...

              Bye
               Kurt