array of hashrefs (nested)

Discussion in 'Perl Misc' started by monkeys paw, Oct 27, 2003.

  1. monkeys paw

    monkeys paw Guest

    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'
    }
     
    monkeys paw, Oct 27, 2003
    #1
    1. Advertising

  2. monkeys paw <> wrote:
    [...]
    > for my $heading (sort keys %pair) {
    > @tags = ();


    You want: my @tags = ();

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


    --
    Glenn Jackman
    NCF Sysadmin
     
    Glenn Jackman, Oct 27, 2003
    #2
    1. Advertising

  3. monkeys paw

    monkeys paw Guest

    Glenn Jackman wrote:

    > monkeys paw <> wrote:
    > [...]
    >> for my $heading (sort keys %pair) {
    >> @tags = ();

    >
    > You want: my @tags = ();
    >
    > [...]
    >> What is causing the 'tags' => $VAR1->[0]{'tags'}, line to
    >> show up?? I would expect it to be

    >

    Thanks Glenn, that does work. Not sure why tho??
     
    monkeys paw, Oct 27, 2003
    #3
  4. monkeys paw

    Roy Johnson Guest

    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.
     
    Roy Johnson, Oct 27, 2003
    #4
  5. monkeys paw <> wrote in message news:<xbbnb.40819$Fm2.16610@attbi_s04>...
    > 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
     
    James E Keenan, Oct 27, 2003
    #5
  6. monkeys paw <> wrote:

    > 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...


    > 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,
    > };
    > }



    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Oct 27, 2003
    #6
  7. monkeys paw

    monkeys paw Guest


    > monkeys paw <> wrote:
    >
    >> 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...
    >


    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.

    >
    >> 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,
    >> };
    >> }

    >
    >
     
    monkeys paw, Oct 27, 2003
    #7
  8. monkeys paw

    Ben Morrow Guest

    wrote:
    > 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

    --
    For the last month, a large number of PSNs in the Arpa[Inter-]net have been
    reporting symptoms of congestion ... These reports have been accompanied by an
    increasing number of user complaints ... As of June,... the Arpanet contained
    47 nodes and 63 links. [ftp://rtfm.mit.edu/pub/arpaprob.txt] *
     
    Ben Morrow, Oct 28, 2003
    #8
  9. monkeys paw wrote:
    >>monkeys paw <> wrote:
    >>
    >>
    >>>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...
    >>

    >
    >
    > 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

    >
    > Anyway, just wanted to make sure i wasn't missing something on
    > this corrolary...thanks again for the help.
    >
    >
    >>> 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,
    >>> };
    >>> }

    >>
    >>

    >
     
    Chris Mattern, Oct 28, 2003
    #9
  10. monkeys paw

    Bob Walton Guest

    monkeys paw wrote:

    >>monkeys paw <> wrote:

    ....


    >> 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.
    >
    >
    >>> 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,
    >>> };
    >>> }

    ....


    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.
    --
    Bob Walton
    Email: http://bwalton.com/cgi-bin/emailbob.pl
     
    Bob Walton, Oct 28, 2003
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Russ Perry Jr
    Replies:
    2
    Views:
    4,282
    Russ Perry Jr
    Aug 20, 2004
  2. Chad E. Dollins
    Replies:
    3
    Views:
    680
    Kai-Uwe Bux
    Nov 8, 2005
  3. Matija Papec

    grouping hashrefs to trees

    Matija Papec, Nov 16, 2003, in forum: Perl Misc
    Replies:
    1
    Views:
    81
    Ben Morrow
    Nov 16, 2003
  4. Sam
    Replies:
    6
    Views:
    182
    Anno Siegel
    Jun 15, 2005
  5. John W. Krahn

    sorting an array of hashrefs

    John W. Krahn, Aug 29, 2006, in forum: Perl Misc
    Replies:
    1
    Views:
    103
    monkeys paw
    Aug 29, 2006
Loading...

Share This Page