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

Is it possible to use foreach in the conditional part of a elsif statement? For example something like

elsif (foreach (@pmis) {if ($_ eq $outdate{$key1} && $lec eq $outdate{ +$key1})}){ ........ }
If this sort of thing is not possible I can work around it by several elsif statements so this is more out of interest than anything else.

Replies are listed 'Best First'.
Re: Regarding the conditional part of eslif (or if) statement
by moritz (Cardinal) on Sep 12, 2010 at 16:02 UTC
    Is it possible to use foreach in the conditional part of a elsif statement?

    No. for and foreach are not expressions, but expressions statements, thus can't be used where a return value is expected.

    But you can always use map, grep or any or all, the last two from List::MoreUtils. In Perl 5.10 and newer the smart-match operator might also be a good choice.

    Perl 6 - links to (nearly) everything that is Perl 6.
Re: Regarding the conditional part of eslif (or if) statement
by ikegami (Patriarch) on Sep 12, 2010 at 16:00 UTC

    You need an expression, something that can return a value. If you use something that doesn't return a value (like foreach), how could the elsif decide whether to enter or not? Your foreach doesn't even have a body, which makes even less sense.

    elsif ($lec eq $outdate{$key1}) { foreach (@pmis) { if ($_ eq $outdate{$key1}) { ........ } } }
Re: Regarding the conditional part of eslif (or if) statement
by ramjamman (Sexton) on Sep 12, 2010 at 16:16 UTC

    Thanks for your answers

    I did have doubts about it being possible. I will write with several elsif statements one for each value of the array.

    Thanks again monks for a speedy resolution.

      I will write with several elsif statements one for each value of the array

      Surely you're missing something here, why not run a foreach on the array and in that test the values, or try another thing? What you describe sounds so very un-programmatic, that I suggest reviewing the logic flow of the program at that point, and see how it could be generalised into a loop.

      "Principle of Least Astonishment: Any language that doesn’t occasionally surprise the novice will pay for it by continually surprising the expert..

      You've been shown a number of solutions already that make what you suggest unnecessary. There are other solutions too, if you cared to elaborate on the context.

      I did have doubts about it being possible.

      Of course it's possible. As several wise monks have pointed out, it's also a Very Bad (and rather pointless) Idea unless you are in contention for the Jerk of the Year award from your fellow programmers, especially those who will have to maintain your code after you 'leave' (read: 'get fired for doing stuff like this').

      But it's possible:

      >perl -wMstrict -le "my @pmis = qw(foo bar baz quux); if (do { for (@pmis) { if (/(.)\1/) { print; } } 1; }) { print q{well, that's done}; } " foo quux well, that's done
Re: Regarding the conditional part of eslif (or if) statement
by ramjamman (Sexton) on Sep 19, 2010 at 05:15 UTC

    Thanks Again Monks.

    I see as usual there is more than one way to tackle any problem including being a bad coder LOLS. I did go for the extra elsif statements in the end as shown in the code below as there was only 4 elements in the array.

    my $y =1; foreach my $key1 (sort keys %outdate) { if ($outdate{$key1} eq $tacho) { $worksheet1->write_blank($r, $y, $tachosquare); } if ($outdate{$key1} eq $mot) { $worksheet1->write_blank($r, $y, $motsquare); } if ($outdate{$key1} eq $motlec) { $worksheet1->write_blank($r, $y, $motlecsquare); } foreach (@pmis) { if($outdate{$key1} eq $_){ $worksheet1->write_blank($r, $y, $pmisquare); } } if ($lec) { if ($lec eq $outdate{$key1} && $tacho eq $outdate{$key1} ) { $worksheet1->write($r, $y, "L", $tacholecsquare); } elsif ($pmis[0] eq $outdate{$key1} && $lec eq $outdate{$key1} ){ $worksheet1->write($r, $y, "L", $pmilecsquare); } elsif ($pmis[1] eq $outdate{$key1} && $lec eq $outdate{$key1} ){ $worksheet1->write($r, $y, "L", $pmilecsquare); } elsif ($pmis[2] eq $outdate{$key1} && $lec eq $outdate{$key1} ){ $worksheet1->write($r, $y, "L", $pmilecsquare); } elsif ($pmis[3] eq $outdate{$key1} && $lec eq $outdate{$key1} ){ $worksheet1->write($r, $y, "L", $pmilecsquare); } else { if ($outdate{$key1} eq $lec) { $worksheet1->write($r, $y, "L", $lecsquare); } } } $y++; }

    I could not at the time get my head around a more logical way of writing it

    note this code is inside a bigger while loop

      Just looking at your
      if ($lec){ #... }
      block. As has been suggested replacing all those near indentical elsif blocks with a loop would be better.

      If you have a default, set it at the begining and avoid an else block.

      For within a small scope it also worth using a temp var to hold the value of a var with a long name that will be used many times. This also uses a temp "holding" var ($cell) so that the write method only appears once.

      This approach helps eliminate a lot of repitition which can be confusing and hard to maintain. And it cuts down typing. :-)

      # give ourselves a short name # in a short scope my $o = $outdate{$key1}; if ($lec and $lec = $o) { # set the default my $cell = $lecsquare; if ($tacho eq $o) { $cell = $tacholecsquare; } else { for my $i (0..3){ $cell = $pmilecsquare if $pmis[$i] eq $o; } } $worksheet1->write($r, $y, "L", $cell); }
        Thanks wfsp you showed me the logic I was missing at the time.

        I also thank you for reminding me to cut down on typing.

        for my $i (0..3){ $cell = $pmilecsquare if $pmis[$i] eq $o; }
        should be the following to be equivalent:
        for my $i (0..3){ if ($pmis[$i] eq $o) { $cell = $pmilecsquare; last; } }
        which can be simplified to
        for (@pmis){ if ($_ eq $o) { $cell = $pmilecsquare; last; } }