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?

6
  • What do you mean, "sometimes"? If you make an array out of $forename and $surname, it always has two elements. Commented Jan 31, 2018 at 21:35
  • So how do I ensure it only loops once if $surname is empty? Commented Jan 31, 2018 at 21:38
  • my @selectedNames = grep {defined and length } ( $forename, $surname ); Commented Jan 31, 2018 at 21:40
  • @Сухой27 grep { length } ... is enough. Commented Jan 31, 2018 at 21:43
  • Yes, length is enough. perl 5.10 complains though stackoverflow.com/a/1481979/223226 Commented Jan 31, 2018 at 21:45

2 Answers 2

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 ''.

Sign up to request clarification or add additional context in comments.

3 Comments

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.
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.
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.
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
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.