Home > Archive > PERL CGI Beginners > August 2007 > packing an array of hashes
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
packing an array of hashes
|
|
| Chris Cosner 2007-08-07, 9:55 pm |
| I've re-read perlref and have been trying to tease an answer out of the
Perl Cookbook.
If you put a hash reference into an array
push @array, \%hash;
you do not store any actual hash data in the array.
So if you change the hash, then later pull the hash reference from the
array and access it, you get changed data.
If you do this in a loop, you store an array of references to the exact
same hash, rather than lots of different hashes.
At least, this seems to be what's happening to me in the pseudo code below:
Question: Is there an efficient way (resembling push @array, \%hash) to
do this that will work? Or do I need to 'unpack' the hash into key =>
value notation to truly add the hash as an element in an array?
while ( condition ) {
(add data to %address)
push @addresses, \%address;
# print statement here shows the hash is different each time
through the loop
}
for (@addresses){
%h = %{$_};
for (keys %h) {
print "$_ = $h{$_}\n";
# print statement here prints the same hash over and over
}
Thanks,
-Chris
| |
| Mr. Shawn H. Corey 2007-08-07, 9:55 pm |
| Chris Cosner wrote:
> If you put a hash reference into an array
> push @array, \%hash;
> you do not store any actual hash data in the array.
> So if you change the hash, then later pull the hash reference from the
> array and access it, you get changed data.
push @array, { %hash };
This creates an anonymous hash and populates it with the contents of %hash. It makes a copy of %hash. Of course, if %hash has any references, they will be copied but not their contents.
--
Just my 0.00000002 million dollars worth,
Shawn
"For the things we have to learn before we can do them, we learn by doing them."
Aristotle
| |
| rcook@pcug.org.au 2007-08-07, 9:55 pm |
| > I've re-read perlref and have been trying to tease an answer out of the
> Perl Cookbook.
>
> If you put a hash reference into an array
> push @array, \%hash;
> you do not store any actual hash data in the array.
> So if you change the hash, then later pull the hash reference from the
> array and access it, you get changed data.
> If you do this in a loop, you store an array of references to the exact
> same hash, rather than lots of different hashes.
> At least, this seems to be what's happening to me in the pseudo code
> below:
>
> Question: Is there an efficient way (resembling push @array, \%hash) to
> do this that will work? Or do I need to 'unpack' the hash into key =>
> value notation to truly add the hash as an element in an array?
>
> while ( condition ) {
> (add data to %address)
> push @addresses, \%address;
> # print statement here shows the hash is different each time
> through the loop
> }
>
> for (@addresses){
> %h = %{$_};
> for (keys %h) {
> print "$_ = $h{$_}\n";
> # print statement here prints the same hash over and over
> }
>
You have sort of solved it yourself.
# print statement here shows the hash is different each time through the loop
NO, it shows the data in the hash is different each time through, the hash
reference is the same reference
# print statement here prints the same hash over and over
YES, that's because the same hash reference is being stored.
Just need differentiating between a reference and its data
Owen
| |
| Chris Cosner 2007-08-07, 9:55 pm |
| Aha. Many thanks.
Now I'm on the right track (see Anonymous Data in the Perl Cookbook, ch.
11).
Mr. Shawn H. Corey wrote:
> Chris Cosner wrote:
>
> push @array, { %hash };
>
> This creates an anonymous hash and populates it with the contents of
> %hash. It makes a copy of %hash. Of course, if %hash has any
> references, they will be copied but not their contents.
>
>
| |
| Paul Lalli 2007-08-08, 6:55 pm |
| On Aug 7, 7:47 pm, ccos...@stanford.edu (Chris Cosner) wrote:
> I've re-read perlref and have been trying to tease an answer out of the
> Perl Cookbook.
>
> If you put a hash reference into an array
> push @array, \%hash;
> you do not store any actual hash data in the array.
> So if you change the hash, then later pull the hash reference from the
> array and access it, you get changed data.
> If you do this in a loop, you store an array of references to the exact
> same hash, rather than lots of different hashes.
> At least, this seems to be what's happening to me in the pseudo code below:
>
> Question: Is there an efficient way (resembling push @array, \%hash) to
> do this that will work? Or do I need to 'unpack' the hash into key =>
> value notation to truly add the hash as an element in an array?
>
> while ( condition ) {
> (add data to %address)
> push @addresses, \%address;
> # print statement here shows the hash is different each time
> through the loop
>
> }
Shawn already gave you one answer. Allow me to point out that if your
comment "(add data to %address)" actually means to reassign the entire
hash, rather than to just add or delete elements from the hash, then
the far more correct solution is to just scope your variables
correctly:
my @addresses;
while (keep_going()) {
my %address = ( ... => ..., ... => .... );
push @addresses, \%address;
}
instead of:
my @addresses;
my %address;
while (keep_going()) {
%address = ( ... => ..., ... => .... );
push @addresses, \%address;
}
This way, as soon as one iteration of your loop ends, the %address
that was declared in that iteration goes away, and you get a brand new
hash the next time around.
If, however, you're only modifying an existing hash, then Shawn's
solution is the only correct one:
my @addresses;
my %address;
while (keep_going() ) {
$address{...} = ....;
push @addresses, { %address };
}
Paul Lalli
| |
|
|
|
|
|