array of hashrefs (nested)

M

monkeys paw

I have the following code that is behaving stragely:

use Data::Dumper;

%pair = (
'Subject' => 'Vapor,Bob-war,new-tag',
'Analyst' => 'simi'
);

for my $heading (sort keys %pair) {
@tags = ();
for my $tag (split /,/, $pair{$heading}) {
push @tags, {tag_key => $tag, tag_name => $tag};
}
push @headings, {
heading_name => $heading,
tags => \@tags,
};
}
print Dumper(\@headings) ;

The output is:

HAT2: $VAR1 = [
{
'tags' => [
{
'tag_key' => 'Vapor',
'tag_name' => 'Vapor'
},
{
'tag_key' => 'Bob-war',
'tag_name' => 'Bob-war'
},
{
'tag_key' => 'new-tag',
'tag_name' => 'new-tag'
}
],
'heading_name' => 'Analyst'
},
{
'tags' => $VAR1->[0]{'tags'},
'heading_name' => 'Subject'
}
];

What is causing the 'tags' => $VAR1->[0]{'tags'}, line to
show up?? I would expect it to be

'tags' => {
'tag_key' => 'new-tag',
'tag_name' => 'new-tag'
}
 
R

Roy Johnson

You are using a reference to a global variable, @tags, which you are
overwriting each pass through the loop.
use strict;
would have helped. Then you would have known to declare it as "my" and
it probably would have given you the results you were expecting.

VAR1 is Dumper's name for the reference to @tags.
 
J

James E Keenan

monkeys paw said:
I have the following code that is behaving stragely:

use Data::Dumper;

%pair = (
'Subject' => 'Vapor,Bob-war,new-tag',
'Analyst' => 'simi'
);

for my $heading (sort keys %pair) {
@tags = ();
for my $tag (split /,/, $pair{$heading}) {
push @tags, {tag_key => $tag, tag_name => $tag};
}
push @headings, {

You obviously were not running with 'use strict;' called. Otherwise
you would have gotten a compilation error right here.
heading_name => $heading,
tags => \@tags,
};
}
print Dumper(\@headings) ;

The output is:

HAT2: $VAR1 = [
{
'tags' => [
{
'tag_key' => 'Vapor',
'tag_name' => 'Vapor'
},
{
'tag_key' => 'Bob-war',
'tag_name' => 'Bob-war'
},
{
'tag_key' => 'new-tag',
'tag_name' => 'new-tag'
}
],
'heading_name' => 'Analyst'
},
{
'tags' => $VAR1->[0]{'tags'},
'heading_name' => 'Subject'
}
];

What is causing the 'tags' => $VAR1->[0]{'tags'}, line to
show up?? I would expect it to be

'tags' => {
'tag_key' => 'new-tag',
'tag_name' => 'new-tag'
}

Once I properly scoped all variables with 'my' and used strict, I got
these results:

$VAR1 = [
{
'heading_name' => 'Analyst',
'tags' => [
{
'tag_name' => 'simi',
'tag_key' => 'simi'
}
]
},
{
'heading_name' => 'Subject',
'tags' => [
{
'tag_name' => 'Vapor',
'tag_key' => 'Vapor'
},
{
'tag_name' => 'Bob-war',
'tag_key' => 'Bob-war'
},
{
'tag_name' => 'new-tag',
'tag_key' => 'new-tag'
}
]
}
];

jimk
 
T

Tad McClellan

monkeys paw said:
I have the following code that is behaving stragely:


If you drive without your seatbelt fastened, then you should
be prepared for a trip through the windshield. :)

use strict;

would have saved you from this problem...
 
M

monkeys paw

If you drive without your seatbelt fastened, then you should
be prepared for a trip through the windshield. :)

use strict;

would have saved you from this problem...

Thanks all for the advice. Upon closer inspection i understand
how localizing the @tags array would save me this problem. However,
just as a side note, "use strict" would not detect this error that
i see. I was overwriting a global, which is perfectly legal.

Anyway, just wanted to make sure i wasn't missing something on
this corrolary...thanks again for the help.
 
B

Ben Morrow

Thanks all for the advice. Upon closer inspection i understand
how localizing the @tags array would save me this problem. However,
just as a side note, "use strict" would not detect this error that
i see. I was overwriting a global, which is perfectly legal.

....except under strictures :). That is of course not strictly (sic)
true: it is perfectly possible to use package globals under 'strict',
bit you must make it clear that you meant to and haven't simply made a
mistake by either declaring them with 'our' or fully qualifying the
name.

Ben
 
C

Chris Mattern

monkeys said:
Thanks all for the advice. Upon closer inspection i understand
how localizing the @tags array would save me this problem. However,
just as a side note, "use strict" would not detect this error that
i see. I was overwriting a global, which is perfectly legal.

Except that when you do "use strict;", Perl doesn't merrily assume
that all your undeclared variables are globals. You have to declare
them as either local (my) or global (global) or whatever. Strict
will kill the compilation if you attempt to use a variable you haven't
declared. "use strict" doesn't stop you from hanging yourself, but it
does at least make you write a requisition order for the rope.

Chris Mattern
 
B

Bob Walton

monkeys said:
....



Thanks all for the advice. Upon closer inspection i understand
how localizing the @tags array would save me this problem. However,
just as a side note, "use strict" would not detect this error that
i see. I was overwriting a global, which is perfectly legal.

Anyway, just wanted to make sure i wasn't missing something on
this corrolary...thanks again for the help.
....


I think perhaps you still don't understand. Here is a short program and
its output that illustrates the essence of the problem:

@array=(1,2,3);
$array_ref1=\@array;
@array=(4,5,6);
$array_ref2=\@array;
print @$array_ref1,"\n";
print @$array_ref2,"\n";

D:\junk>perl junk401.pl
456
456

D:\junk>

The problem (if you wish to call it a problem -- it is expected and
documented behavior) is that $array_ref1 and $array_ref2 are references
to the *exact same array*, the one called @array. The fact that the
*contents* of this array changed do not make the references change what
array they are pointing to. There *is only one* array, with two
references pointing to it. Hence when you're all done, both references
point to the same set of values. If you had 100 references, they would
all point to the same array.

Now, use strict; will in and of itself not fix this:

use warnings;
use strict;
my @array;
@array=(1,2,3);
my $array_ref1=\@array;
@array=(4,5,6);
my $array_ref2=\@array;
print @$array_ref1,"\n";
print @$array_ref2,"\n";

gives:

D:\junk>perl junk401a.pl
456
456

D:\junk>

And for the very same reasons. One can add a "my" to each array
definition and solve the problem:

use warnings;
use strict;
my @array=(1,2,3);
my $array_ref1=\@array;
my @array=(4,5,6);
my $array_ref2=\@array;
print @$array_ref1,"\n";
print @$array_ref2,"\n";

which gives:

D:\junk>perl junk401b.pl
"my" variable @array masks earlier declaration in same scope at
junk401.pl line 5.
123
456

D:\junk>

but at the expense of a warning. So how should this be handled? One
good approach is to do what you meant to do: make a reference to an
anonymous copy of the array each time, like:

use warnings;
use strict;
my @array;
@array=(1,2,3);
my $array_ref1=[@array];
@array=(4,5,6);
my $array_ref2=[@array];
print @$array_ref1,"\n";
print @$array_ref2,"\n";

which gives the desired:

D:\junk>perl junk401c.pl
123
456

D:\junk>

Previous posters have mentioned that use strict; would point out the
problem. Not really, in this case, although, since @tags was defined in
a loop, saying my @tags; would have solved the immediate problem -- but
not if there had been a reference taken to the array, a modification to
the array, and then another reference during the execution of the loop.
But use strict; is hugely beneficial for many many problems, and
should *always* be used, along with use warnings; , in all development code.

HTH.
 

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
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top