Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: Removing array items and resizing the array

I’m trying to filter an array of terms using another array in Perl. I have Perl 5.18.2 on OS X, though the behavior is the same if I use 5.010. Here’s my basic setup:

#!/usr/bin/perl
#use strict;
my @terms = ('alpha','beta test','gamma','delta quadrant','epsilon',
             'zeta','eta','theta chi','one iota','kappa');
my @filters = ('beta','gamma','epsilon','iota');
foreach $filter (@filters) {
    for my $ind (0 .. $#terms) {
        if (grep { /$filter/ } $terms[$ind]) {
            splice @terms,$ind,1;
        }
    }
}

This works to pull out the lines that match the various search terms, but the array length doesn’t change. If I write out the resulting @terms array, I get:

[alpha]
[delta quadrant]
[zeta]
[eta]
[theta chi]
[kappa]
[]
[]
[]
[]

As you might expect from that, printing scalar(@terms) gets a result of 10.

What I want is a resulting array of length 6, without the four blank items at the end. How do I get that result? And why isn’t the array shrinking, given that the perldoc page about splice says, “The array grows or shrinks as necessary.”?

(I’m not very fluent in Perl, so if you’re thinking “Why don’t you just...?”, it’s almost certainly because I don’t know about it or didn’t understand it when I heard about it.)

like image 789
Eric A. Meyer Avatar asked Mar 11 '23 10:03

Eric A. Meyer


1 Answers

You can always regenerate the array minus things you don't want. grep acts as a filter allowing you to decide which elements you want and which you don't:

#!/usr/bin/perl

use strict;

my @terms = ('alpha','beta test','gamma','delta quadrant','epsilon',
           'zeta','eta','theta chi','one iota','kappa');
my @filters = ('beta','gamma','epsilon','iota');

my %filter_exclusion = map { $_ => 1 } @filters;

my @filtered = grep { !$filter_exclusion{$_} } @terms;

print join(',', @filtered) . "\n";

It's pretty easy if you have a simple structure like %filter_exclusion on hand.

Update: If you want to allow arbitrary substring matches:

my $filter_exclusion = join '|', map quotemeta, @filters;

my @filtered = grep { !/$filter_exclusion/ } @terms;
like image 92
tadman Avatar answered Mar 20 '23 20:03

tadman