Re: Accessing an AoHoAoH
by calin (Deacon) on Jun 05, 2004 at 19:07 UTC
|
| [reply] [d/l] [select] |
|
|
use [ ... ] instead of ( ... )
right. It's not a simple array but a reference to a nameless array.
See also perldoc perllol,
perldoc perlreftut, perldoc perlref and perldoc perldata for more syntactical details (the usual suspects =))
| [reply] |
|
|
It's not a simple array but a reference to a nameless array
Just to be exact, it's not a "simple array" either. It's a list, which is not quite the same as an array. You can read about the differences by running perldoc -q "a list and" at a command prompt, or by viewing an online copy.
| [reply] [d/l] |
|
|
Just to make things clear (well, it had me stumped for awhile), calin means replacing the () in the values of your page hashes by []. That way, you're assigning an anonymous array to the value of the hash, instead of a list, as you are currently doing.
BTW, the @AoH assignment throws a warning:
Odd number of elements in anonymous hash at aoh.pl line 21.
That is because of the parentheses instead of square brackets.
As to your second question: it's an array of hashes one of whose values is an array of hashes. So, in a sense, it is a AoHoAoH :)
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
| [reply] |
|
|
my @one_d = ( (1,2,3), (4,5,6), (7,8,9) );
is really just a single list. You have to use braces:
my @two_d = ( [1,2,3], [4,5,6], [7,8,9] );
I prefer to use a reference to an anonymous array for the outside container, maily because there is no mixing of
parens and braces, square or curly:
my $two_d = [ [1,2,3], [4,5,6], [7,8,9] ];
When in doubt, always consult Data::Dumper. Always! If you had used Data::Dumper on your data structure,
you would have seen that the problem was within it:
print Dumper \@AoH;
__END__
(it's an AoHoH ... not an AoHoAoH)
$VAR1 = [
{
'page' => {
'paragraph' => 'lesson1'
},
'chapter' => 'Basic',
'HASH(0x8638dec)' => undef
},
{
'HASH(0x86fee04)' => undef,
'page' => {
'paragraph' => 'lesson3'
},
'chapter' => 'Advanced'
}
];
Finally, print out a copy of References quick reference. And don't forget about Data::Dumper! :)
| [reply] [d/l] [select] |
|
|
|
|
|
|
I guess I'm still a little confused about when to use parens and when to use brackets.
Parens build a list, brackets build an anonymous array, and return a reference to it. Hashes can only contain scalars as values, so a list won't ever do (except when it contains only one item — but then you don't need a list). An array reference is a scalar, so that will work. As it's the only thing that actually does work properly, Perl's syntax has been optimized to ease access to array references as hash and array values.
$x->{'foo'}[1] actually means: use $x as a hash reference, get the value associated with the string 'foo'. Use this as an array reference and access the second element (with index 1) from it.
Actually you can even split this up into:
$aref = $x->{'foo'};
$aref->[1]
provided you didn't need autovivification, which were to happen in case $x->{'foo'} was undefined, in the former case — but not in the latter. | [reply] [d/l] [select] |
|
|
| [reply] |
Re: Accessing an AoHoAoH
by dimar (Curate) on Jun 05, 2004 at 21:17 UTC
|
A couple of thoughts:
1) As a stylistic preference, whenever I construct
a nested data variable in perl, I always start
with a scalar variable at the top, like '$dataroot'.
I like
the way it looks and it's flexible, since a scalar can hold
a reference to anything. You'll notice that
Data::Dumper does the same thing when it spits
out ($VAR1 $VAR2 etc..) as the topmost 'container'
of the output.
2) Using the style mentioned above helps me focus
more on the *meaning* of what it is I am really
storing, helps keeps things readable.
Given this style, your example becomes this
slightly different code ...
use strict;
use warnings;
my $chapters = [
{
title => 'Basic',
page => [
{ paragraph => 'lesson1'},
{ paragraph => 'lesson2'},
],
},
{
title => 'Advanced',
page => [
{ paragraph => 'lesson3'},
{ paragraph => 'lesson4'},
],
},
];
### since we started with a scalar to hold
### an anonymous array ref, we have to
### use the little 'arrow' notation
print $chapters->[0]{title}; ### basic
print "\n---------------\n";
print $chapters->[1]{title}; ### advanced
print "\n---------------\n";
print $chapters->[1]{page}[0]{paragraph}; ### lesson3
print "\n---------------\n";
print $chapters->[1]{page}[1]{paragraph}; ### lesson4
print "\n---------------\n";
| [reply] [d/l] |
|
|
Good stuff, scooterm. Observation: with the scalar, it's brackets all the way.
Question: does assigning the data structure to the scalar automatically make it a reference? So, there's no need to:
$chapters = \$chapters;
Right? Thanks.
—Brad "A little yeast leavens the whole dough."
| [reply] [d/l] |
|
|
You guessed it. You get to use square brackets for an array, and curly braces for an hash, and the syntax stays consistent thru the whole thing, no matter how deeply your data gets nested.
The only time it gets a little 'funky' is when you want to treat your data like a regular array, for example, in a foreach loop. Actually, perldsc lays it all out.
### here we tell perl to treat the scalar as a ref
### to an array.
foreach my $item (@{$chapters}){
print $item->{title};
}
Side note: Data::Dumper is absolutely a plus. Sprinkle it into every script where you use a complex variable, in fact, sprinkle it everywhere. It's very useful.
| [reply] [d/l] |
|
|
Assigning a reference to a scalar.. makes the scalar contain a reference! Theres no need to "initialize with a reference to itself as you seem to think. You do need to actually initialize something with a reference before you try to dereference it, unless strict is off.
| [reply] |
Re: Accessing an AoHoAoH
by CountZero (Bishop) on Jun 05, 2004 at 19:48 UTC
|
Do not assign the reference to your structure to an array (@AoH) but to a scalar. Putting an array creates an extra level of an array in it which you do not need. Use Data::Dumper to see this.
CountZero "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law
| [reply] [d/l] |
|
|
CountZero, not sure I understand. Ran Data::Dumper and got:
$VAR1 = {
'chapter' => 'Basic',
'page' => [
{
'paragraph' => 'lesson1'
},
{
'paragraph' => 'lesson2'
}
]
};
$VAR2 = {
'chapter' => 'Advanced',
'page' => [
{
'paragraph' => 'lesson3'
},
{
'paragraph' => 'lesson4'
}
]
};
What am I missing? Thanks
—Brad "A little yeast leavens the whole dough."
| [reply] [d/l] |
|
|
That's what you should get if you write something like
dump @AoH; because @AoH "flattens"
to a one-element list in the list context of the function call.
(This was just a guess, but I'm sure in what I'll write below.)
This way, however, you can not easily access the contents of
the deep datastructure, as you can't index the array in such a
way that it flattens automatically, so you have to use a
0 as a first array index, just as CountZero said.
To change, either use a scalar variable, or (perhaps better)
use an array variable, just assign it like
@AoH= ({...}, {...}, ...);, not @AoH= [{...}, {...}, ...];.
| [reply] [d/l] [select] |
|
|
|
|
| [reply] [d/l] [select] |
Re: Accessing an AoHoAoH
by FoxtrotUniform (Prior) on Jun 07, 2004 at 18:30 UTC
|
On the subject of style: I like to decompose nested-structure dereferences into "sensical" single-layer dereferences, as below:
#! /usr/bin/perl -w
use strict;
my @AoH=( { chapter => "Basic",
page => [
{ paragraph => "lesson1"},
{ paragraph => "lesson2"}
]
},
{ chapter => "Advanced",
page => [
{ paragraph => "lesson3"},
{ paragraph => "lesson4"}
]
}
);
foreach my $ch (@AoH) {
print $ch->{'chapter'}, "\n";
my $page = $ch->{'page'};
foreach my $paras (@$page) {
print "\t", $paras->{'paragraph'}, "\n";
}
}
I find this makes code using these structures easier to read, although longer. It's a judgement call as to whether your structure is dense enough to warrant the extra code.
(I also like to use -> for every deref and single-quote every hash key, but that's a whole different issue....)
--
F
o
x
t
r
o
t
U
n
i
f
o
r
m
Found a typo in this node? /msg me
% man 3 strfry
| [reply] [d/l] [select] |