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

Is there a more elegant or nicer looking way to do what this code below does?

I have a varying length array that needs to be sent to a subroutine, but only with three elements at a time.

#!/usr/bin/perl -w use strict; use Data::Dumper; # need to split up this array and send three values at a time to # sub "do_someting" my @array = qw( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ); while (@array) { my @array_segment; # if element isn't defined, don't get the NULL values push @array_segment, shift @array; push @array_segment, shift @array if defined $array[0]; push @array_segment, shift @array if defined $array[0]; do_something(@array_segment); } sub do_something { my @array = @_; print Dumper \@array; }

Replies are listed 'Best First'.
Re: Send Array to Subroutine, Three Elements at a Time
by GrandFather (Saint) on Oct 24, 2007 at 03:06 UTC

    splice is the answer. Consider:

    #!/usr/bin/perl -w use strict; my @array = qw( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ); do_something (splice @array, 0, 3) while @array; sub do_something { print "@_\n"; }

    Prints:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

    Perl is environmentally friendly - it saves trees
Re: Send Array to Subroutine, Three Elements at a Time
by dragonchild (Archbishop) on Oct 24, 2007 at 03:29 UTC
    This is actually the example used in the POD for List::MoreUtils natatime().
    use List::MoreUtils qw( natatime ); my $it = natatime 3, @array; while ( my @vals = $it->() ) { do_something( @vals ); }

    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: Send Array to Subroutine, Three Elements at a Time
by BrowserUk (Patriarch) on Oct 24, 2007 at 03:22 UTC

    If you don't want to destroy the array with splice:

    [0] Perl> sub do3{ print "@_" };; [0] Perl> @a = 1 .. 20;; [0] Perl> do3 @a[ $_ .. $_ +2 ] for map{ $_ * 3 } 0 .. $#a / 3;; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Use of uninitialized value in join or string at (eval 3) line 1, <STDI +N> line 3. 19 20

    If your array might not be a multiple of 3, then you'll need to take appropriate precautions inside the sub.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Send Array to Subroutine, Three Elements at a Time
by runrig (Abbot) on Oct 24, 2007 at 02:56 UTC
    splice three elements at a time from the array.
Re: Send Array to Subroutine, Three Elements at a Time
by petdance (Parson) on Oct 24, 2007 at 03:28 UTC
    splice is indeed the way to go. Also, what you're doing with:
    push @array_segment, shift @array if defined $array[0];
    isn't really right, because what if the first element of @array is undef itself? You wanted this:
    push @array_segment, shift @array if @array;
    That's also more idiomatic, because you're saying "if there are more elements in the array" rather than "if the first element is undef".

    But the splice is the way to go.

    xoxo,
    Andy

Re: Send Array to Subroutine, Three Elements at a Time
by aquarium (Curate) on Oct 24, 2007 at 03:01 UTC
    Just curious...why is there a need to send three elements of an array at a time?....when you could just send a reference to the whole array and have the function step through it, three at a time if needed.
    the hardest line to type correctly is: stty erase ^H
      I have some legacy code that takes the array, formats it and sends it out in a SMS text message.

      But the array that gets texted out can only be 3 elements long before the text message format breaks.