0

I want to loop over an array of strings, but sometimes if the string is empty, it still gets added as an item.

my $forename = $service->getValue('forename');
my $surname = $service->getValue('surname');

my @selectedNames = ( $forename, $surname );

foreach my $name (@selectedNames) {
    # do something

    if ($trackedName) {
         # log the name
    } else {
         # log a FATAL
    }
}

If the string is empty for $surname, then it shouldn't loop the second time at all, but it always does. How do I prevent this?

melpomene
  • 84,125
  • 8
  • 85
  • 148
snakespan
  • 1,183
  • 2
  • 15
  • 33

2 Answers2

1

Concerning Frank Förster's response (I don't have enough reputation to reply directly):

Wouldn't grepping using $_ also strip any numeric item with the value 0, and the string "0"? I realize you're not likely to get them as "surnames", but not being prepared for such an eventuality may lead to bugs that are hard to track.


Edit: Here's my solution (after prompting by PerlDuck):

my $forename = $service->getValue('forename');
my $surname = $service->getValue('surname');

my @selectedNames = ( $forename, $surname );

foreach my $name (@selectedNames) {
    next  if (not defined $name  or  $name eq '');

    # do something

    if ($trackedName) {
        # log the name
    } else {
        # log a FATAL
    }
}

Alternately you can just use the original code, but substitute

foreach my $name (@selectedNames)

with

foreach my $name (grep { defined and $_ ne '' } @selectedNames)

If you're worried your "empty" names may include stuff with just whitespace in them, you can use $name =~ /^\s*$/ instead of $name eq ''.

Silvar
  • 705
  • 3
  • 8
  • I'd love to upvote this, but as it stands it's not a complete answer. And, yes, `"0"` and `0` would be skipped with the `grep {$_} @array` code. – PerlDuck Feb 01 '18 at 16:45
  • Nice work. `grep { defined $_ && /\S/ } @names` is an easy way to require non-whitespace elements in your filter. You can also just say `grep {defined && /\S/} @names`, because $_ is assumed for `defined`. – daotoad Feb 01 '18 at 20:39
  • Nice! `/\S/` is quite elegant. I rarely think to use the negative character class escapes - more often than not I end up using ridiculously complicated constructs with the positive ones, in the style of `/(?!\s)./`. I definitely need to work on this. – Silvar Feb 01 '18 at 22:37
0

Just use next unless ($name); as first line of your loop.

Perl handles the values undef and empty string ('') as false and will therefore enter the next loop.

my $forename = $service->getValue('forename');
my $surname = $service->getValue('surname');

my @selectedNames = ( $forename, $surname );

foreach my $name (@selectedNames) {
    next unless ($name);

    # do something

    if ($trackedName) {
         # log the name
    } else {
         # log a FATAL
    }
}

If you want to use grep to filter the list actually you neither need length nor defined: grep { $_ } (@selectedNames) would be enough. Therefore your code would look like

my $forename = $service->getValue('forename');
my $surname = $service->getValue('surname');

my @selectedNames = ( $forename, $surname );

foreach my $name (grep { $_ } @selectedNames) {
    # do something

    if ($trackedName) {
         # log the name
    } else {
         # log a FATAL
    }
}
Frank Förster
  • 371
  • 1
  • 4