in reply to if ... elsif ... else
I'll address optimisation first. If your $from .. $to range is only some hundreds or even a few thousand, then it's probably not worth even looking at optimising. If the range is orders of magnitude larger, or if the loop shown is an inner loop of a larger construct, or if it's part of a subroutine called in another loop, then optimisation may be worthwhile.
If you do decide to optimise, use the builtin Benchmark module. Run your benchmarks several times — I typically use a minimum of five runs — and throw away outlier results. If it's not absolutely clear that one method is substantially faster than another, assume that there's no optimisation. It's generally better to start out without preconceived ideas about which method will be quicker: that way, you can take the results on face value; won't be disappointed that your pre-benchmark guess was wrong; and won't be tempted to make false assumptions about the results.
On to condensing the code. Succinct code can be easier to read simply because there's less to read and understand; however, avoid falling into the trap of being too clever and producing a maintenance nightmare. Jamming lots of code into a small space to save a few lines is rarely useful: it makes no difference to Perl, so you get no benefits there; it does, however, make a huge difference to humans — code that's hard to read is hard to understand and maintain — that's true for first-time viewers as well as the original author revisiting after some weeks or months.
I'd generally avoid writing code like that posted; however, if I did need to, I'd probably aim to lay it out in some tabular format, like:
if (CONDITION) { ACTION } elsif (CONDITION) { ACTION } ... elsif (CONDITION) { ACTION } else { ACTION }
I was able, without resorting to any cleverness, to reduce your code to this single statement:
$_ % 2 or $_ % 3 or $_ % 4 or $_ % 5 or say for $from .. $to;
I'll run through each step, from your seven lines to my one, as that may help you to do the same with other code. I used the range 0 .. 120 throughout, purely for test purposes. Here's your original:
$ perl -wE 'foreach my $i ( 0 .. 120 ) { if ($i % 2 != 0) { next; } el +sif ($i % 3 != 0) {next; } elsif ($i % 4 != 0) {next; } elsif ($i % 5 + != 0) {next; } else { say $i;} }' 0 60 120
If "$i % N != 0" is TRUE, then "$i % N" must be TRUE, so we can remove the " != 0" part throughout:
$ perl -wE 'foreach my $i ( 0 .. 120 ) { if ($i % 2) { next; } elsif ( +$i % 3) {next; } elsif ($i % 4) {next; } elsif ($i % 5) {next; } else + { say $i;} }' 0 60 120
Instead of having a next statement for every condition, we can use a single next statement with a multiple condition (cf. your first two responses[1,2]):
$ perl -wE 'foreach my $i ( 0 .. 120 ) { next if $i % 2 or $i % 3 or $ +i % 4 or $i % 5; say $i; }' 0 60 120
"next if CONDITION; say $i;" is the same as "say $i unless CONDITION;", so we can get rid of next altogether and reduce the code in the loop to a single statement:
$ perl -wE 'foreach my $i ( 0 .. 120 ) { say $i unless $i % 2 or $i % +3 or $i % 4 or $i % 5; }' 0 60 120
foreach and for are synonymous and $_ will be used if you don't supply a variable:
$ perl -wE 'for ( 0 .. 120 ) { say unless $_ % 2 or $_ % 3 or $_ % 4 o +r $_ % 5; }' 0 60 120
The "unless CONDITION" part is a Statement Modifier. As it says in the documentation, in emphasised, uppercase text, we can only use a "SINGLE" modifier. Unfortunately, "for LIST" is also a statement modifier, and we want that in the final result. Getting rid of unless is easy:
$ perl -wE 'for ( 0 .. 120 ) { $_ % 2 or $_ % 3 or $_ % 4 or $_ % 5 or + say; }' 0 60 120
Now we can use "for LIST" as a modifier, reducing the block to a single statement:
$ perl -wE '$_ % 2 or $_ % 3 or $_ % 4 or $_ % 5 or say for 0 .. 120' 0 60 120
— Ken
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
| A reply falls below the community's threshold of quality. You may see it by logging in. |