ewok
ewok

Reputation: 21503

perl: filtering with grep, including warnings for filtered values

I want to filter an array using grep, but I want to include a warning for all filtered values, rather than silently filtering them out. I've tried this:

my @l = (1,2,3,4,5);
@l = grep {
  if ($_%2 == 0) {
    warn "$_ is an even number!!!";
    return 0;
  }
  return 1;
} @l;

But this doesn't work. I get no warnings, and the list isn't filtered. How can I do this?

Upvotes: 0

Views: 199

Answers (3)

vanHoesel
vanHoesel

Reputation: 954

KISS

don't try to be to smart, grep is indeed the right thing for creating a new list out of an existing list, using a positive match. Yes, you can do all sorts of fancy things inside.

but what is wrong with an ordinary foreach? just loop over the list, do whatever intelligent selection and push the positives onto another list. and you have an entire code block available to handle the ones you don't need and make super interesting warnings for different kind off reasons...

foreach my $item ( @numbers ) {
    if ( $item %2 ) {
        warn "fiz";
        next
    }
    unless ( $item % 3 ) {
        warn "buzz";
        next
    }
    push @good, $item
}

and everyone a few days later can tell what is happening here

Upvotes: 0

Sobrique
Sobrique

Reputation: 53508

You do get warnings (you do need to use warnings; use strict; though):

Can't return outside a subroutine

This is because grep takes an expression or a block - it's not strictly a sub.

This will work:

#!/usr/bin/env perl
use strict;
use warnings;

my @numbers = ( 1, 2, 3, 4, 5 );
my @odd_numbers = grep {
    if ( $_ % 2 == 0 ) {
        warn "even number $_";
        0;
    }
    else {
        1;
    }

} @numbers;

print @odd_numbers;

Also: Don't use single letter variable names. It's bad style.

Upvotes: 2

ikegami
ikegami

Reputation: 386696

That code dies with

Can't return outside a subroutine at a.pl line 10.

The callback isn't a subroutine. You can't use return.

my @l = (1,2,3,4,5);
@l = grep {
  if ($_ % 2) {
    1
  } else {
    warn "even number!!!";
    0
  }
} @l;

Printing even number!!! more than once isn't that useful.

my @nums = 1..5;
my @odds = grep { $_ % 2 } @nums;
warn("One or more even numbers!\n") if @odds != @nums;

Upvotes: 1

Related Questions