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

Hello Monks,

My question is this. I am looking for a more Perl-ish way to accomplish the following:
NUMBER: for (3 .. 8) { my $pdu_num = $_; $pdu_num = 11 - $pdu_num unless defined $order; while (@nodes) { my $node = shift @nodes; $map{$node} = $pdu . '['.$pdu_num.']'; next NUMBER; } }
What's happening here is I need to increment one item of a list (the for...) and append it to the end of an element of the array, then skip to the next number and pair it up with the next element of the array. The $order variable is a flag to determine whether I need to arrange them in ascending (3..8) or descending (11 -n) order.

Another disturbing fact is the loop label. While I recognize that this is valid in Perl, it has a haunting goto-statement quality about it. Improvements?
Also, would it be considered more Perl-ish to write:
for my $pdu_num (3 .. 8) { while my $node (@nodes) { # more code here... } }
I couldn't think of a better way to word my title, although I'm sure there is probably a term for what I'm doing here.
Thanks in advance for your time and replies.
This message brought to you by the complexities of Avocent AlterPath ACS.

Replies are listed 'Best First'.
Re: More effective way to increase two elements of a list in parallel?
by moritz (Cardinal) on May 06, 2008 at 17:56 UTC
    I didn't quite understand what you try to achieve so just a stylistic remark:

    The inner while is useless, because after the first iteration it will always leave the inner while. You could write it this way instead:

    for (3 .. 8) { my $pdu_num = $_; $pdu_num = 11 - $pdu_num unless defined $order; if (@nodes) { my $node = shift @nodes; $map{$node} = $pdu . '['.$pdu_num.']'; next; } }

    Now you don't have nested loops anymore, so you don't need the label for next. (Actually you don't need the next at all, because it's the last statement in that loop)

    Update: another slightly improved version:

    for (3 .. 8) { my $pdu_num = $_; $pdu_num = 11 - $pdu_num unless defined $order; last unless @nodes; my $node = shift @nodes; $map{$node} = $pdu . '['.$pdu_num.']'; }
      Moritz,
      Thank you. This is more or less exactly what I was looking for. I come from a C-ish background, so the idioms and syntax of Perl leave me stumbling sometimes.
      Thanks again!
Re: More effective way to increase two elements of a list in parallel?
by dragonchild (Archbishop) on May 06, 2008 at 18:01 UTC
    my @pdu_nums = 3 .. 8; if ( $order ) { @pdu_nums = reverse @pdu_nums; } # You could check that @nodes >= @pdu_nums here, too. foreach my $pdu_num ( @pdu_nums ) { my $node = shift @nodes; unless ( $node ) { die "A horrible death!\n"; } $map{ $node} = join '', $pdu, '[', $pdu_num, '}'; }
    Or did I miss something? If I didn't, then the following may also work (and isn't destructive to @nodes). It does assume that the size of @nodes and @pdu_nums is identical and that %map is being created here.
    use List::MoreUtils qw( pairwise ); my @pdu_nums = 3 .. 8; @pdu_nums = reverse @pdu_nums if $order; %map = { $b => "${pdu}[${a}]" } pairwise @pdu_nums, @nodes;

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: More effective way to increase two elements of a list in parallel?
by locked_user sundialsvc4 (Abbot) on May 07, 2008 at 03:02 UTC

    (Shrug...)

    “Perlish” or not, is it abundantly clear? With a suitable addition of comments, “I think so.”

    What I'd really want to see, as “the unfortunate soul who's trying to pick-up after you, after you (poor thing...) got smooshed by that bread-truck,” is a nice, crystal-clear explanation of just exactly where you're headed with that concatenation: $pdu . ''.$pdu_num.''. Where am I gonna see that again? How is that value going to be used? If I needed to change the format of that string, what's gonna break?

    You generally don't get Brownie points for being “clever,” nor even for being “efficient.” What enamors you(r memory) to your mourners co-workers is ... simple clarity.

    “The computer is really, really fast. We know that.   I'm not (anymore).  ;-)  Don't make me try to ‘figure out’ what you were thinking, nor why.” Do that for me, and I shall forever say about you:   “Such a nice person. Too bad about that bread-truck...”

Re: More effective way to increase two elements of a list in parallel?
by wade (Pilgrim) on May 06, 2008 at 18:09 UTC

    I see a few things, here.

    First, you should always use:

    use strict; use warnings; use diagnostics; # not everyone puts this in but I think it's helpful

    But that's just general stuff. The big question I have is why use a while (especially with the -- eesh -- next statement) when an if is really what you want? Rewriting this using your (excellent) suggestion of the reformulated for:

    foreach my $pdu_num (3 .. 8) { $pdu_num = 11 - $pdu_num unless defined $order; if (my $node = shift @nodes) { $map{$node} = $pdu . '['.$pdu_num.']'; } }

    gives, I think, a much clearer chunk of code

    --
    Wade
      Note that
      if (my $node = shift @nodes) { $map{$node} = $pdu . '['.$pdu_num.']'; }

      is not the same as the OP's code. Your code won't process the if if the first element of @nodes is false. Better to use

      if (@nodes) { my $node = shift @nodes; $map{$node} = $pdu . '['.$pdu_num.']'; }


      Unless I state otherwise, all my code runs with strict and warnings
Re: More effective way to increase two elements of a list in parallel?
by chrism01 (Friar) on May 07, 2008 at 01:03 UTC
Re: More effective way to increase two elements of a list in parallel?
by et_alia (Initiate) on May 06, 2008 at 18:29 UTC
    Many thanks to all who replied (or will reply)! I jumped the gun when I only thanked the top poster.

    Cheers.