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


In reply to Re: if ... elsif ... else by kcott
in thread if ... elsif ... else by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.