Reputation: 33
Hey fellow perl monks,
I'm still wrapping my head around how to correctly dereference. (I read the similar posts prior to posting, but unfortunately am still a bit cloudy on the concept.)
I have the following array, which internally is composed of two arrays. (BTW, I am using strict and warning pragmas.)
use strict; use warnings;
my @a1; my @a2;
where:
@a1 = ( "1MB", "2MB", ... )
and..
@a2 = ( "/home", "/home/debug", ... )
Both @a1 & @a2 are arrays which contain 51 rows. So, I populate these into my 2nd array.
my @b;
push (@b, [ @a1, @a2 ]);
However, when I try to print the results of @b:
sub newl { print "\n"; print "\n"; }
my $an1; my @an1;
$an1 = $#a1;
@an1 = ( 0, 1..$an1 );
for my $i (@an1) { print @b[$i]; &newl; }
I see references to the arrays:
ARRAY(0x81c0a10)
.
ARRAY(0x81c0a50)
.
.
.
How do I properly print this array? I know I need to dereference the array, I'm not sure how to go about doing this. I tried populating my array as such:
push (@b, [ \@a1, \@a2 ]);
Which produces the same results. I also tried:
for my $i (@an1) { print @{$b[$i]}; &newl; }
Which unfortunately errors due to having 0 as an array reference?
Can't use string ("0") as an ARRAY ref while "strict refs" in use at p_disk_ex6.pl line 42.
Any suggestions are greatly appreciated!
Upvotes: 0
Views: 2968
Reputation: 163
If you want a general solution that doesn't assume how many elements there are in each of the sub-arrays, and which also allows arbitrary levels of nesting, you're better off using packages that someone else has already written for displaying recursive data structures. A particularly prevalent one is YAML, which you can install if you don't already have it by running cpan:
$ cpan
Terminal does not support AddHistory.
cpan shell -- CPAN exploration and modules installation (v1.9800)
Enter 'h' for help.
cpan[1]> install YAML
Then you can display arbitrary data structures easily. To demonstrate with a simple example:
use YAML;
my @a1 = qw(1MB 2MB 10MB 7MB);
my @a2 = qw(/foo /bar /flub /blub);
my @b = (\@a1, \@a2);
print Dump(\@b);
results in the output
---
-
- 1MB
- 2MB
- 10MB
- 7MB
-
- /foo
- /bar
- /flub
- /blub
For a slightly more complicated example
my @b = (\@a1, \@a2,
{ a => 0, b => 1 } );
gives
---
-
- 1MB
- 2MB
- 10MB
- 7MB
-
- /foo
- /bar
- /flub
- /blub
- a: 0
b: 1
To read this, the three "-" characters in column 1 indicate an array with three elements. The first two elements have four sub elements each (the lines with "-" in column 3). The third outer element is a hash reference, since it is made up of "key: value" pairs.
A nice feature about YAML is that you can use it to dump any recursive data structure into a file, except those with subroutine references, and then read it back later using Load.
If you really have to roll your own display routine, that is certainly possible, but you'll have a much easier time if you write it recursively. You can check whether your argument is an array reference or a hash reference (or a scalar reference) by using ref:
my @a1 = qw(1MB 2MB 10MB 7MB);
my @a2 = qw(/foo /bar /flub /blub);
my @b = (\@a1, \@a2,
{ a => 0, b => 1 } );
print_recursive(\@b);
print "\n";
sub print_recursive {
my ($obj) = @_;
if (ref($obj) eq 'ARRAY') {
print "[ ";
for (my $i=0; $i < @$obj; $i++) {
print_recursive($obj->[$i]);
print ", " if $i < $#$obj;
}
print " ]";
}
elsif (ref($obj) eq 'HASH') {
print "{ ";
my @keys = sort keys %$obj;
for (my $i=0; $i < @keys; $i++) {
print "$keys[$i] => ";
print_recursive($obj->{$keys[$i]});
print ", " if $i < $#keys;
}
print " }";
}
else {
print $obj;
}
}
which produces the output
[ [ 1MB, 2MB, 10MB, 7MB ], [ /foo, /bar, /flub, /blub ], { a => 0, b => 1 } ]
I have not written my example code to worry about pretty-printing, nor does it handle scalar, subroutine, or blessed object references, but it should give you the idea of how you can write a fairly general recursive data structure dumper.
Upvotes: 0
Reputation: 3491
Even Simply this also works
use strict;
use warnings;
my @a1 = qw(1MB 2MB 10MB 7MB);
my @a2 = qw(/foo /bar /flub /blub);
my @b = (@a1, @a2);
print "@b";
Upvotes: 0
Reputation: 85
A short example program, which might help you:
use strict;
use warnings;
my @a1 = qw(1MB 2MB 10MB 7MB);
my @a2 = qw(/foo /bar /flub /blub);
my @b = (\@a1, \@a2);
# equivalent long version:
# my @b = ();
# $b[0] = \@a1;
# $b[1] = \@a2;
for (my $i = 0; $i <= $#a2; $i++) {
print "a1[$i]: $b[0][$i]\n";
print "a2[$i]: $b[1][$i]\n";
print "\n";
}
In your example you were pushin an anoymous arrayref [] into @b. Therefore $b[0] contained the arrayref.
my @b;
push (@b, [ \@a1, \@a2 ]);
# this corresponds to:
# $b[0][0] = \@a1;
# $b[0][1] = \@a2;
In the example where you wrote [@a1, @a2] you were creating an array_ref which contained the joined arrays @a1 and @a2 (first all elements of @a1, and then all elements of @a2):
my @b;
push(@b , [@a1, @a2]);
# $b[0] = ['1MB' , '2MB', '10Mb', '7MB', '/foo', '/bar', '/flub', '/blub']
Upvotes: 1