adding to an array of hashes

T

Tom

When I run the following:

for($k=0;$k<3;$k++){
$r[$k]->{'NUM'} = $k;
#$temp->{'NUM'} = $k;
#$r[$k] = $temp;
print "added: $r[$k]->{'NUM'}\n";
}

foreach $t (@r){
print "$t->{'NUM'}\n";
}

I get the intended output:

added: 0
added: 1
added: 2
0
1
2

Then I uncomment the commented lines and comment out the
"$r[$k]->{'NUM'} = $k;" line...or, in words, I use a temporary value
to hold the hash before assigning it adding it to the array of hashes.
The output comes out like:

added: 0
added: 1
added: 2
2
2
2

Why is that? I'm probably using scalar assignments when I shouldn't
be, but I don't understand why this happens. How can it be
accomplished with a temporary value?
 
J

John J. Trammell

When I run the following:

for($k=0;$k<3;$k++){
$r[$k]->{'NUM'} = $k;
#$temp->{'NUM'} = $k;
#$r[$k] = $temp;
print "added: $r[$k]->{'NUM'}\n";
}

Try this (untested):

for($k=0;$k<3;$k++){ # for my $k (0..2) {
my $temp = { NUM => $k };
$r[$k] = $temp;
print "added: $r[$k]->{'NUM'}\n";
}

"perldoc -f my" has some details. One question: do you "use strict;"?

Or you might want to try (also untested):

my @r = map { NUM => $_ }, 0..2;
 
B

Brian McCauley

Subject: adding to an array of hashes

Your question has nothing to do with adding to an array of hashes
for($k=0;$k<3;$k++){
$temp->{'NUM'} = $k;
$r[$k] = $temp;
}

foreach $t (@r){
print "$t->{'NUM'}\n";
}
2
2
2

Why is that? I'm probably using scalar assignments when I shouldn't
be, but I don't understand why this happens.

There is a reason why we keep telling people to enable strictures and
warnings and to declare all variables in the smallest applicable
lexical scope. Can you guess what it is?
How can it be accomplished with a temporary value?

By using a proper _temporary_ variable.

Just because you called your variable $temp does not tell the compiler
that it is temporary.

You are evidently assuming that $temp contains undef at the start of
each interation of the loop so that $temp->{'NUM'}=$k will autovivify
a new hash.

But $temp is a global variable that is set on the first iteration of
the loop and never changes thereafter. Every time you set
$temp->{'NUM'}=$k you are setting the same thing.

If you had used my() to declare an appropriately scoped temporary
variable the problem would not occur.

Alternatively you could explicitly undef($temp) on each iteration but
that's not, in general, a good technique.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
H

Helgi Briem

Just because you called your variable $temp
does not tell the compiler that it is temporary.

He he.

A line destined to become part of a thousand .sigs.
 
T

Tom

There is a reason why we keep telling people to enable strictures and
warnings and to declare all variables in the smallest applicable
lexical scope. Can you guess what it is?

Thanks for the condescending remark, but it wouldn't have helped.
Scope wasn't what I was confused about; I was aware $temp was global
and had intended it that way...
You are evidently assuming that $temp contains undef at the start of
each interation of the loop so that $temp->{'NUM'}=$k will autovivify
a new hash.

But $temp is a global variable that is set on the first iteration of
the loop and never changes thereafter. Every time you set
$temp->{'NUM'}=$k you are setting the same thing.

So no, I didn't expect a new $temp hash to be created on each
iteration. My mistake was expecting the "$r[$k] = $temp;" line to copy
$temp's value over into a new variable, rather than have $r[$k] just
point to it. Nonetheless, the suggestions to use my() within the
iterations made me realize this, so thanks.
 
T

Tom

bd said:
Since you're putting references in the array, they all point to the same
hash.

Thanks, that's what I didn't know. It's references that's placed into
the array, not a copy of $temp.
#!/usr/bin/perl -w
use strict;

my @r;
for(my $k = 0; $k < 3; $k++){
my $temp; # $temp is local to each iteration of the loop, and set to undef
# Note that this is not the same as the 'local' keyword
$temp->{NUM} = $k;
$r[$k] = $temp;
print "added: $r[$k]->{'NUM'}\n";
}

foreach my $t (@r) {
print "$t->{NUM}\n";
}
 
T

Tom

rather than have $r[$k] just
point to it.

$r[$k] doesn't point to $temp, it points to what $temp points to.
(or, more accurately, refers to what $temp refers to).

oh! I see. I don't see why I didn't make the connection to C pointers
earlier... thanks. That explains a lot.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,293
Messages
2,571,505
Members
48,192
Latest member
LinwoodFol

Latest Threads

Top