perl

Delete an array element completely


Goal: Remove a particular value from an array

I have written a script, and it works fine, but I am not happy the way I have written it. So I am curious to know is there a better way to write it. Please consider the below use case:

I have a nested hash/hash/array...like below. I need to remove any array values which has local in their name:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my $hash = { esx1 =>
                    { cluster   => "clu1",
                      fd        => "fd1",
                      ds        => [
                                        'ds1',
                                        'ds2',
                                        'localds',
                                    ],
                    },
            esx2 =>
                    { cluster   => "clu2",
                      fd        => "fd2",
                      ds        => [
                                        'ds3',
                                        'ds4',
                                        'dslocal',
                                    ],
                    },
            };


foreach my $a ( keys %$hash )
{
    foreach ( 0..$#{ $hash->{$a}->{ds} } )
    {
        delete $hash->{$a}->{ds}->[$_] if $hash->{$a}->{ds}->[$_] =~ /local/i;
        @{ $hash->{$a}->{ds} } = grep defined, @{ $hash->{$a}->{ds} };
    }
}

print Dumper ($hash);

so the script deletes the "localds" and "dslocal" and keeps everything else intact.

  1. Is there a cleaner way to write the foreach ( 0..$#{$hash->{$a}->{ds} } ) loop?
  2. If I do not write the grep line above, the resultant array has the value containing local deleted, but it is replaced by undef. Why is this happening?

Solution

  • It isn't necessary to first iterate through the array and delete elements and then look for "not-deleted" nodes (side note: this grep should be outside the loop).

    You can look for good nodes from the very start! Replace the entire loop with:

    foreach my $a ( keys %$hash )
    {
        @{ $hash->{$a}->{ds} } = grep { !/local/i } @{ $hash->{$a}->{ds} };
    }