Deleting blank elements from a list

Discussion in 'Perl Misc' started by Just in, Jul 2, 2004.

  1. Just in

    Just in Guest

    If I do this:-

    use strict;
    use warnings;

    my @Arr1 = split /\D+/, $Str1;
    my @Arr2 = split /\D+/, $Str2;

    foreach my $i(0..$#Arr1)
    {
    foreach my $j(0..$#Arr2)
    {
    if($Arr1[$i] eq $Arr2[$j])
    {
    delete $Arr2[$j];
    }
    }
    }

    In some instances @Arr2 ends up looking like this ('', '', 'Value3',
    Value4', '')

    How can I make @Arr2 = ('Value3', 'Value4') i.e. $#Arr2 == 1
    rather than 4?

    Cheers,
    Just in
     
    Just in, Jul 2, 2004
    #1
    1. Advertising

  2. Just in

    Bob Walton Guest

    Just in wrote:

    > If I do this:-
    >
    > use strict;
    > use warnings;
    >
    > my @Arr1 = split /\D+/, $Str1;
    > my @Arr2 = split /\D+/, $Str2;
    >
    > foreach my $i(0..$#Arr1)
    > {
    > foreach my $j(0..$#Arr2)
    > {
    > if($Arr1[$i] eq $Arr2[$j])
    > {
    > delete $Arr2[$j];
    > }
    > }
    > }
    >
    > In some instances @Arr2 ends up looking like this ('', '', 'Value3',
    > Value4', '')
    >
    > How can I make @Arr2 = ('Value3', 'Value4') i.e. $#Arr2 == 1
    > rather than 4?
    >
    > Cheers,
    > Just in



    You could use the splice() function instead of delete() to remove
    element from @Arr2 instead of just undef'ing them like delete() does:

    perldoc -f splice

    But you should really revamp your entire algorithm, since it is way slow
    (order n^2). Maybe something like:

    {
    my %h;
    @h{@Arr2}=(0..$#Arr2);
    delete @h{@Arr1};
    @Arr2=sort {$h{$a}<=>$h{$b}} keys %h;
    }

    You could apply the Schwarzian Transform to the sort to further improve
    the efficiency.

    --
    Bob Walton
    Email: http://bwalton.com/cgi-bin/emailbob.pl
     
    Bob Walton, Jul 2, 2004
    #2
    1. Advertising

  3. Just in wrote:
    > If I do this:-
    >
    > use strict;
    > use warnings;
    >
    > my @Arr1 = split /\D+/, $Str1;
    > my @Arr2 = split /\D+/, $Str2;
    >
    > foreach my $i(0..$#Arr1)
    > {
    > foreach my $j(0..$#Arr2)


    To increase efficiency and prevent uninitialized warnings:

    foreach my $j (reverse 0..$#Arr2)

    > {
    > if($Arr1[$i] eq $Arr2[$j])
    > {
    > delete $Arr2[$j];


    splice @Arr2, $j, 1;

    > }
    > }
    > }
    >
    > In some instances @Arr2 ends up looking like this ('', '',
    > 'Value3', Value4', '')
    >
    > How can I make @Arr2 = ('Value3', 'Value4') i.e. $#Arr2 == 1
    > rather than 4?


    See suggestions above. You should also study

    perldoc -q duplicate

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
     
    Gunnar Hjalmarsson, Jul 2, 2004
    #3
  4. Just in wrote:
    >
    > If I do this:-
    >
    > use strict;
    > use warnings;
    >
    > my @Arr1 = split /\D+/, $Str1;
    > my @Arr2 = split /\D+/, $Str2;


    You should probably use the match operator for that so that you don't
    get an empty string as the first element of the array.

    my @Arr1 = $Str1 =~ /\d+/g;
    my @Arr2 = $Str2 =~ /\d+/g;


    > foreach my $i(0..$#Arr1)
    > {
    > foreach my $j(0..$#Arr2)
    > {
    > if($Arr1[$i] eq $Arr2[$j])
    > {
    > delete $Arr2[$j];
    > }
    > }
    > }
    >
    > In some instances @Arr2 ends up looking like this ('', '', 'Value3',
    > Value4', '')


    It would look more like (undef, undef, 'Value3', 'Value4', undef)


    > How can I make @Arr2 = ('Value3', 'Value4') i.e. $#Arr2 == 1
    > rather than 4?


    This will do what you want:

    my $regex = qr[\b@{[ join '|', $Str1 =~ /\d+/g ]}\b];
    my @Arr2 = grep !/$regex/, $Str2 =~ /\d+/g;



    John
    --
    use Perl;
    program
    fulfillment
     
    John W. Krahn, Jul 2, 2004
    #4
  5. Just in wrote:
    >
    > If I do this:-
    >
    > use strict;
    > use warnings;
    >
    > my @Arr1 = split /\D+/, $Str1;
    > my @Arr2 = split /\D+/, $Str2;


    You should probably use the match operator for that so that you don't
    get an empty string as the first element of the array.

    my @Arr1 = $Str1 =~ /\d+/g;
    my @Arr2 = $Str2 =~ /\d+/g;


    > foreach my $i(0..$#Arr1)
    > {
    > foreach my $j(0..$#Arr2)
    > {
    > if($Arr1[$i] eq $Arr2[$j])
    > {
    > delete $Arr2[$j];
    > }
    > }
    > }
    >
    > In some instances @Arr2 ends up looking like this ('', '', 'Value3',
    > Value4', '')


    It would look more like (undef, undef, 'Value3', 'Value4', undef)


    > How can I make @Arr2 = ('Value3', 'Value4') i.e. $#Arr2 == 1
    > rather than 4?


    This will do what you want:

    my $regex = qr[\b(?:mad:{[ join '|', $Str1 =~ /\d+/g ]})\b];
    my @Arr2 = grep !/$regex/, $Str2 =~ /\d+/g;


    John
    --
    use Perl;
    program
    fulfillment
     
    John W. Krahn, Jul 2, 2004
    #5
  6. Just in

    dutone Guest

    Gunnar Hjalmarsson <> wrote in message news:<>...
    > Just in wrote:
    > > If I do this:-
    > >
    > > use strict;
    > > use warnings;
    > >
    > > my @Arr1 = split /\D+/, $Str1;
    > > my @Arr2 = split /\D+/, $Str2;
    > >
    > > foreach my $i(0..$#Arr1)
    > > {
    > > foreach my $j(0..$#Arr2)

    >
    > To increase efficiency and prevent uninitialized warnings:
    >
    > foreach my $j (reverse 0..$#Arr2)
    >
    > > {
    > > if($Arr1[$i] eq $Arr2[$j])
    > > {
    > > delete $Arr2[$j];

    >
    > splice @Arr2, $j, 1;
    >
    > > }
    > > }
    > > }
    > >
    > > In some instances @Arr2 ends up looking like this ('', '',
    > > 'Value3', Value4', '')
    > >
    > > How can I make @Arr2 = ('Value3', 'Value4') i.e. $#Arr2 == 1
    > > rather than 4?

    >
    > See suggestions above. You should also study
    >
    > perldoc -q duplicate



    You suggested....

    To increase efficiency and prevent uninitialized warnings:
    foreach my $j (reverse 0..$#Arr2)

    Can you tell me how this will increase efficiency?

    Thanks
     
    dutone, Jul 3, 2004
    #6
  7. dutone wrote:
    > Gunnar Hjalmarsson wrote:
    >>To increase efficiency and prevent uninitialized warnings:
    >>
    >> foreach my $j (reverse 0..$#Arr2)

    >
    > Can you tell me how this will increase efficiency?


    Fewer iterations under certain conditions, and (I think) more accurate
    result. Please consider this code:

    my $Str1 = '1 2 3 4 5';
    my $Str2 = '1 1 2 2 6';
    my $iter;

    my @Arr1 = split /\D+/, $Str1;
    my @Arr2 = split /\D+/, $Str2;

    for my $i (0..$#Arr1) {
    for my $j (0..$#Arr2) {
    if ($Arr1[$i] eq $Arr2[$j]) {
    splice @Arr2, $j, 1;
    }
    $iter++;
    }
    }

    print "Left in \@Arr2: @Arr2\n";
    print "$iter iterations\n";

    Besides a couple of "uninitialized" warnings it outputs:
    Left in @Arr2: 1 2 6
    18 iterations

    But if you change

    for my $j (0..$#Arr2) {

    to

    for my $j (reverse 0..$#Arr2) {

    it outputs:
    Left in @Arr2: 6
    11 iterations

    (and no warnings).

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
     
    Gunnar Hjalmarsson, Jul 3, 2004
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. flupke
    Replies:
    5
    Views:
    370
    Larry Bates
    Oct 29, 2004
  2. Adam Hartshorne
    Replies:
    2
    Views:
    385
    Nitin Motgi
    Jan 27, 2006
  3. Harry Barker
    Replies:
    2
    Views:
    536
    Alf P. Steinbach
    Apr 19, 2006
  4. Arvin Portlock
    Replies:
    2
    Views:
    96
    Arvin Portlock
    Dec 10, 2003
  5. crea
    Replies:
    2
    Views:
    427
    Nobody
    Dec 28, 2012
Loading...

Share This Page