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

I basically wanted to print out submitted form values in a table with two parameters per table row.I had an array of the params so I was wishing I could just say

while (my (@elements)= (some_num_elements of @array){
   print Tr( Td(@elements));
}

Well I was going to use the Perl Cookbook solution but I didn't want to destroy the array shifting multiple elements off. I know I could have extremely easily stored it in an copy and used that but it got me thinking there must be a way to do it. Next thing I know, I had spent a couple of hours on a stupid little detail that could have been coded long hand in about five minutes because the look of an unimportant page vexed me. Oh well.

Here's what I came up with.
#!/usr/bin/perl -w use strict; BEGIN{ my %array_copy = (); # Storage of pristine arrays sub elements(\@;$){ my $no_gc = $_[0]; # Hold onto $_[0] so it doesn't get garbage + collected . my @t = @{$_[0]}; # Temp array as I can't get it to assign to + $array_copy directly. # ie $array_copy {$_[0]} = [ @{$_[0]} ] # Am I missing something? $array_copy {$_[0]} = [@t] unless defined $array_copy{$_[0]}; +# Store if we haven't. my @temp = @{$array_copy {$_[0]}}; $_[1] = 1 unless $_[1] ; # Get one element +if non specified. my @vals = splice(@{$_[0]}, 0, $_[1] ); # Pop elements. if (@vals){ # If elements to r +eturn return @vals; # then return them +. }else{ # Time to restore array back to it's previous self. # Tried @$_[0] = @{$array_copy {$_[0]}} but wouldn't work. # Seemed to temporarily change the reference, only for thi +s statement. @$no_gc = @{$array_copy {$_[0]}}; # Array now restored. delete $array_copy{$_[0]}; # Free array copy return ; } } } # The following is a silly example but it shows that calls to elements + can be # nested. Also, passing an element count is optional, it will default +to 1 element my @array1 = (1..15); my @array2 = (1..5); print "\@array1",join(", ", @array1),"\n"; print "\@array2",join(", ", @array2),"\n\n"; while (my @v = elements(@array1,3)){ print join(", ", @v),"\n"; print "-" x 30,"\n"; # Removal of elements from @array are visible here. while (my @x = elements(@array2,@array1) ){ # As this demonstr +ates. print "\t",join(", ", @x),"\n"; print "\t","_" x 30,"\n"; } } print "\@array1",join(", ", @array1),"\n"; print "\@array2",join(", ", @array2),"\n";


I'd be interested if anyone sees any problems with this or ways to improve it, hell I'd be interested to know if anyone could think of any uses for it. For me, it will be handy for spewing tables.

-Lee

"To be civilized is to deny one's nature."

Replies are listed 'Best First'.
Re: Processing Multiple Array Elements
by blakem (Monsignor) on Sep 11, 2001 at 14:49 UTC
    I'm not entirely sure if this is what you are trying to do... However, if all you need to do is loop through an array processing $N elements at a time, wouldn't it be easier to just take some slices with calculated indices?
    #!/usr/bin/perl -wT use strict; my @a = (1..16); # test array my $atatime = 3; # number of elements to loop over for my $i (0..$#a/$atatime) { # loop through @a/$atatime times my $min = $i*$atatime; # index of low element my $max = $min+$atatime-1; # index of high element $max = $#a if $max > $#a; # make sure we don't fall off the end print join(", ", @a[$min..$max]),"\n"; # do something with our slic +e } # Verify that we haven't munged our values print "\nStill There: ", join(' ',@a), "\n"; =output 1, 2, 3 4, 5, 6 7, 8, 9 10, 11, 12 13, 14, 15 16 Still There: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
    Perhaps I don't understand what that nested while loop is demonstrating in your sample code....

    -Blake

      Yeah, it would have been much easier, but I just got it in my head that I should be able to do it THAT way and that it must be possible, so there it is. Now instead the of login code that I should have finished, I have this construct of dubious value.

      The loop was just to show that the nested calls work and if for some reason you thought it was a good thing, that the remainder of the list was visible to any enclosing statements.

      Like I said, I'll probably only using it for spitting out tables.

      update
      A lil example.
      my @dictionary =(lots o words); print start_table(); while(@words = elements(@dictionary, $columns)){ print Tr(td([@words])); } print end_table();
      -Lee

      "To be civilized is to deny one's nature."
Re: Processing Multiple Array Elements
by shotgunefx (Parson) on Sep 12, 2001 at 09:52 UTC
    Like I said, I don't know how useful this is but I found the elements operator cool. Plus it was my first little hack at using prototypes and making something that behaves like a built in.

    Below is an updated version that doesn't not copy the original array to memory, but rather inserts elements as they are removed.

    Should be handy if you want to use this with very large arrays. One problem I see with this is that if you delete elements form the array from an enclosing statement, the original array will be changed as they won't be there to push into temporary storage.