relientmark has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm not sure if "row" is the right word, but I'm trying to work out how to remove a row from a 2Darray based on a match. I've attempted with the following code, although it doesn't work, as the array "shifts" as I remove "rows". I assume I am going about this the wrong way, so any help would be appreciated. I dont want to just blank the row, I want to remove it completely from the array. The array in real life is about 10k rows, and the match criteria would be a variable.

@arr=(['a','b','c','d'],['e','f','g'],['h','i','j'],['e','f','g'],['h' +,'i','j'],['e','f','g'],['h','i','j'],['a','b','c','d'],['a','b','c', +'d']); @arr1 = @arr; for(@arr){print @$_, ":";} print "\n"; $i=-1; for(@arr){ $i++; print "i = $i\n"; if(@$_[0] =~ /e/){ splice(@arr1,$i,1); } } for(@arr1){print @$_, ":";} print "\n";
The desired outcome of the above would be: @arr=('a','b','c','d','h','i','j','h','i','j','h','i','j','a','b','c','d','a','b','c','d')

Replies are listed 'Best First'.
Re: Remove "Row" from multidimensional array
by BrowserUk (Patriarch) on Mar 21, 2011 at 10:39 UTC

    Assuming that what your rather muddled description means is that you want to remove any sub-array from an AoAs if it contains an element that matches the regex /e/, then:

    @arr=( ['a','b','c','d'], ['e','f','g'], ['h','i','j'], ['e','f','g'], ['h','i','j'], ['e','f','g'], ['h','i','j'], ['a','b','c','d'], ['a','b','c','d'] );; $arr[ $_ ] ~~ /e/ and splice @arr, $_, 1 for reverse 0 .. $#arr;; pp \@arr;; [ ["a", "b", "c", "d"], ["h", "i", "j"], ["h", "i", "j"], ["h", "i", "j"], ["a", "b", "c", "d"], ["a", "b", "c", "d"], ]

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Remove "Row" from multidimensional array
by moritz (Cardinal) on Mar 21, 2011 at 10:34 UTC
    The problem with your code is that $i are indexes into @arr, but you use it to delete rows from @arr1.

    That works for the first row to be deleted, but afterwards the indexes differ. Inserting $i--; directly after the call to splice might fix it (haven't tried it though).

    Update: this script seems to work:

    use strict; use warnings; my @arr=(['a','b','c','d'],['e','f','g'],['h','i','j'],['e','f','g'],[ +'h','i','j'],['e','f','g'],['h','i','j'],['a','b','c','d'],['a','b',' +c','d']); my @copy = @arr; my $i=-1; for(@arr){ $i++; if(@$_[0] =~ /e/){ splice(@copy,$i,1); $i--; } } print join (' ', @$_), "\n" for @copy;

    You could also try a non-destructive approach:

    my @arr1 = grep { @$_ !~ /e/ } @arr;

    That is, construct a new array which only those rows you actually want.

Re: Remove "Row" from multidimensional array
by wind (Priest) on Mar 21, 2011 at 15:53 UTC

    It looks like you could use some practice with grep, map, and join, three essential tools for anyone working with arrays.

    Here is a version of your script that does the same thing using these three functions alone. Note that the printing out of the data is slightly different as this version does not include a trailing : after the final row.

    my @arr=( [qw(a b c d)], [qw(e f g)], [qw(h i j)], [qw(e f g)], [qw(h i j)], [qw(e f g)], [qw(h i j)], [qw(a b c d)], [qw(a b c d)], ); print join(':', map {join '', @$_} @arr) . "\n"; my @arr1 = grep {! grep {/e/} @$_} @arr; print join(':', map {join '', @$_} @arr1) . "\n";
    Outputs
    abcd:efg:hij:efg:hij:efg:hij:abcd:abcd abcd:hij:hij:hij:abcd:abcd

    - Miller