Re: my 'if' condition doesn't work, why?
by toolic (Bishop) on Nov 11, 2014 at 21:37 UTC
|
for (my $n = 0; $n < 268; $n++) {
if ($n==40 || $n==47 || $n==76)) {
print $n."\n";
}
}
Another conventional, scalable way is to store your values in a hash and use exists. | [reply] [d/l] |
Re: my 'if' condition doesn't work, why?
by GrandFather (Saint) on Nov 12, 2014 at 01:04 UTC
|
for my $n (0 .. 267) {
print "$n\n" if grep {$n == $_} 40, 47, 76;
}
with the slight down side that the compare is evaluated for each item in the list always. Most of the time that won't be an issue, but if it is (for a large list of possibilities) then you could instead:
my %wanted = map {$_ => 1} 40, 47, 76;
for my $n (0 .. 267) {
print "$n\n" if exists $wanted{$n};
}
Perl is the programming world's equivalent of English
| [reply] [d/l] [select] |
|
|
The core List::Util first function is like grep but returns the first element found:
use List::Util qw(first);
for my $n (0 .. 267) {
print "$n\n" if first {$n == $_} 40, 47, 76;
}
and so should be faster for very large lists.
| [reply] [d/l] [select] |
|
|
A problem with List::Util::first() as used in the example above is that it actually returns the first element from the list that satisfies the condition. If this value happens to be false, the if-statement modifier will not satisfied, and the dependent statement will not be executed. Neither any nor grep nor a hash lookup have this problem.
c:\@Work\Perl>perl -wMstrict -le
"use List::Util qw(first);
;;
for my $n (0 .. 267) {
printf qq{$n } if first {$n == $_} 40, 0, 47, 76;
}
print qq{\n----------};
;;
;;
for my $n (0 .. 267) {
printf qq{$n } if grep { $n == $_ } 40, 0, 47, 76;
}
"
40 47 76
----------
0 40 47 76
| [reply] [d/l] [select] |
|
|
| [reply] |
Re: my 'if' condition doesn't work, why?
by philipbailey (Curate) on Nov 11, 2014 at 21:38 UTC
|
The expression (40||47||76) "short-circuits" and evaluates to 40. Scalar $n is then only compared to 40.
Edit: the solution is as toolic suggests, though I tend to use the low-precedence or operator by default (rather than the high precedence one, ||), as it more often does what I expect.
| [reply] [d/l] [select] |
Re: my 'if' condition doesn't work, why?
by AnomalousMonk (Archbishop) on Nov 11, 2014 at 21:39 UTC
|
The particular expression (40||47||76) evaluates only to one value: 40. That's because of the nature of the logical-or operator; see perlop. Maybe try something like:
c:\@Work\Perl\monks>perl -wMstrict -le
"my %hit = map { $_ => 1 } 40, 47, 76;
;;
for (my $n = 0; $n < 268; $n++) {
if ($hit{$n}) {
print $n;
}
}
"
40
47
76
Update: Or even with a more Perlish for-loop:
c:\@Work\Perl\monks>perl -wMstrict -le
"my %hit = map { $_ => 1 } 40, 47, 76;
;;
for my $n (0 .. 267) {
if ($hit{$n}) {
printf qq{$n };
}
}
"
40 47 76
| [reply] [d/l] [select] |
Re: my 'if' condition doesn't work, why?
by Anonymous Monk on Nov 11, 2014 at 21:43 UTC
|
Yes, you can do it just fine with a regex, and see the other monks' answers. And TIMTOWTDI :-)
use Quantum::Superpositions 'any';
# OR
#use Perl6::Junction 'any';
for (my $n = 0; $n < 268; $n++) {
if ($n == any(40,47,76)) {
print $n."\n";
}
}
| [reply] [d/l] |
|
|
This looks like the 'nicest' (from a code readability and compactness point of view) solution to me, shame that it's not standard Perl but instead requires an extra module.
So I have chosen to use
if ($n==40 || $n==47 || $n==76) {
which works fine too (regardless whether I use 'or' or '||').
Many thanks to all who replied for your help.
| [reply] [d/l] |
|
|
#! perl
use strict;
use warnings;
use List::Util 'any';
for my $n (0 .. 267)
{
print "$n\n" if any { $n == $_ } (40, 47, 76);
}
Update: Fixed off-by-one error in the for loop range, thanks to AnomalousMonk.
Output:
17:34 >perl 1074_SoPW.pl
40
47
76
17:34 >
Hope that helps,
| [reply] [d/l] [select] |
|
|
if ($n ~~ [40, 47, 76]) {
...;
}
However, smart match acts pretty weird in some cases (not the above case), so it is not usually a great idea to use it.
| [reply] [d/l] |