A Perl Chicken-and-egg problem

Richard Dice rdice-e+AXbWqSrlAAvxtiuMwx3w at public.gmane.org
Sat Jun 21 18:58:33 UTC 2008


Hi Paul,

my @A = myobj::files::list(params); // same declaration as in the docs
> foreach $x (@A) {
>    print "$x\n";
> }
>

First, I take it that somewhere on the disk you have a file called myobj/
files.pm and there is a "sub list {...}" within it?  Also, "params" should
be written "@params".

Also, please make sure you "use strict;" and "use warnings;" in your
programs, and then you will need to lexicalize your 'foreach' loop iteration
variables, making it "foreach my $x ( ... ) { ... }".

On to your ultimate code example:


> my @A = myobj::files::list(params);
> foreach $x (@A) {
>    for ($i = 0; $i < 16; $i++) {
>         for $j = 0; $j < 16; $j++) {
>              print "$x->[$i][$j]\n";
>         }
>    }
> }
>
> This kind of works. I get the output I expect, except for one thing. I
> don't know the array size, so I am hard-coding the upper limit of the
> loops. $#x to find the size doesn't work, since (1) $x merely points to
> an array, and (2) the array is two dimensional. Any suggestions?


There are two ways to cope with this.

First, you _can_ continue to work with the C-style approach you have written
above and improve it by using the $#ARRAY syntax, but you need to give the
$#ARRAY syntax what it needs in order to work.

my @A = myobj::files::list(@params);
foreach $x (@A) {
   for ($i = 0; $i < $#{@$x}; $i++) {
        for $j = 0; $j < $#{@{$x->[$i]}; $j++) {
             print "$x->[$i][$j]\n";
        }
   }
}

Here's a small program that might make the technique a bit more explicit.

#!perl

use warnings;
use strict;

my $a = [ 'a' .. 'z', [10 .. 15] ];

print $#{@$a} . "\n";
print $#{@{$a->[$#{@$a}]}} . "\n";
print $a->[ $#{@$a} ][ $#{@{$a->[ $#{@$a} ]}} ] . "\n";

exit 0;

$a is a reference to an array, so it would be analogous to a single element
within your @A array.

I stuff it with the characters 'a' through 'z', which is 26 elements, though
the final element has array element index 25 (since arrays start at index
0).  Then I tack on a 27th element (array index 26), which is itself a
reference to an array which contains the integers 10, 11, 12, 13, 14, 15.
This is a list of 6 elements, so its last index has a value 5.

The output of the program is three lines.  The first line is "26".  The
second line is "5".  The third line is "15".

This is the old C-style of doing things.  Unless you actually need to know
array indices for some other reason then it's not what I would recommend.
Here's a much simpler Perl-style approach.

my @A = myobj::files::list(@params);
 foreach my $x ( @A ) {
    foreach my $y ( @$x ) {
         foreach my $z ( @$y ) {
              print "$z\n";
         }
    }
 }

Other simplifications exist, which may or may not be appropriate to your
situation.  Here are some that would work with this (admittedly myopic)
example:

foreach my $x ( myobj::files::list(@params) ) {
    foreach my $y ( @$x ) {
        print "$_\n" foreach @$y;
    }
 }

In much the same way that it's possible to program FORTRAN in any language,
it's possible to program C in Perl.  I recommend programming Perl in Perl.
:-)  An excellent book if you are interested in getting more into the idioms
of programming Perl-as-Perl is "Perl Cookbook", 2nd Edition, by Torkington
and Christiansen, published by O'Reilly.
http://oreilly.com/catalog/9780596003135/

Cheers,
 - Richard
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://gtalug.org/pipermail/legacy/attachments/20080621/e1c33fd9/attachment.html>


More information about the Legacy mailing list