iterating through a hash map

Discussion in 'Perl Misc' started by Krzysztof Poc, Dec 7, 2011.

  1. ello

    I would like to operate on a "child" elements in following XML
    document.
    Note that "children" tag may not be present. I may access the specific
    child
    element as follows (I use XML::TreePP):

    $tree->{singers}->{album}->[0]->{children}->{child}->[0]

    My question is how can I do my task in a loop. I tried to combine both
    "foreach" and "exists" functions but I failed.

    Great thanks for help.

    <singers>
    <album>
    <surname> John </surname>
    <age> 25 </age>
    <children>
    <child> Alex </child>
    <child> Ares </child>
    </children>
    <dog> small </dog>
    </album>

    <album>
    <surname> Adam </surname>
    <age> 33 </age>
    <children>
    <child> Anita </child>
    <child> Marta </child>
    </children>
    <dog> medium </dog>
    </album>

    <album>
    <surname> Lan </surname>
    <age> 3 </age>
    <dog> noDog </dog>
    </album>

    </singers>
     
    Krzysztof Poc, Dec 7, 2011
    #1
    1. Advertising

  2. On Dec 7, 2:21 pm, Henry Law <> wrote:
    > On 07/12/11 11:25, Krzysztof Poc wrote:
    >
    > > My question is how can I do my task in a loop. I tried to combine both
    > > "foreach" and "exists" functions but I failed.

    >
    > Krzysztof, be assured that it _can_ be done in a loop.  Please show us
    > what you've coded already and we'll show you where you've gone wrong.
    >
    > Standing orders for this forum include "code first, then ask questions".
    > (And also "post a minimal example if you possibly can").
    >
    > --
    >
    > Henry Law            Manchester, England


    Great thanks for feedback.
    I've simplified the schama of an XML file. Now there may be only one
    child sub element
    inside children. I've attached the entire document at the end.

    I wrote the following perl script:

    #! /usr/bin/perl

    use XML::TreePP;
    use Tie::IxHash;

    $tpp = XML::TreePP->new();
    $tree = $tpp->parsefile( "file.xml" );

    if ( exists $tree->{singers}->{album}->{children} ) {
    foreach $elem ( $tree->{singers}->{album}->{children} ) {
    $elem -> {child} = "noChild";
    }
    }



    <singers>
    <album>
    <surname> John </surname>
    <age> 25 </age>
    <children>
    <child> Ares </child>
    </children>
    <dog> small </dog>
    </album>

    <album>
    <surname> Adam </surname>
    <age> 33 </age>
    <children>
    <child> Marta </child>
    </children>
    <dog> medium </dog>
    </album>

    <album>
    <surname> Lan </surname>
    <age> 3 </age>
    <dog> noDog </dog>
    </album>
    </singers>
     
    Krzysztof Poc, Dec 7, 2011
    #2
    1. Advertising

  3. Krzysztof Poc

    Ken Butler Guest

    On Wed, 7 Dec 2011, Ben Morrow wrote:

    > $tree->{singers}{album}[0]{children}{child}[0]
    >
    > (the first is obviously necessary so Perl knows you're talking about a
    > hashref in $tree rather than an element of the hash %tree).
    >
    >> My question is how can I do my task in a loop. I tried to combine both
    >> "foreach" and "exists" functions but I failed.

    >
    > Here's a hint:
    >
    > for my $album ( @{ $tree->{singers}{album} } ) {
    > ...
    > }
    >
    > The @{...} syntax is probably what you were missing. (Yes, we all know
    > it's ugly.) Start by (re-)reading the 'Using References' section of
    > perlreftut.


    This I don't understand. I thought the @{} turned a hash (ref) into an
    array, whose elements are alternately key, value, key, value,... so that
    iterating through the array would *not* simply pull out just the keys.

    My code for the above would say something like

    for my $album (keys %{$tree->{singers}{album}})
    {
    ...
    }

    Does that do the same thing as de-reffing the hash ref into an array? If
    so, why? (Time to go read perlreftut again, I think.)

    Cheers,
    Ken.
     
    Ken Butler, Dec 7, 2011
    #3
  4. Ken Butler <> writes:
    > On Wed, 7 Dec 2011, Ben Morrow wrote:
    >
    >> $tree->{singers}{album}[0]{children}{child}[0]
    >>
    >> (the first is obviously necessary so Perl knows you're talking about a
    >> hashref in $tree rather than an element of the hash %tree).
    >>
    >>> My question is how can I do my task in a loop. I tried to combine both
    >>> "foreach" and "exists" functions but I failed.

    >>
    >> Here's a hint:
    >>
    >> for my $album ( @{ $tree->{singers}{album} } ) {
    >> ...
    >> }
    >>
    >> The @{...} syntax is probably what you were missing. (Yes, we all know
    >> it's ugly.) Start by (re-)reading the 'Using References' section of
    >> perlreftut.

    >
    > This I don't understand. I thought the @{} turned a hash (ref) into an
    > array, whose elements are alternately key, value, key, value,... so
    > that iterating through the array would *not* simply pull out just the
    > keys.


    But $tree->{singers}{album} isn't a hash reference its an array
    reference. At least, your attempt at subscripting it strongly suggests
    this.
     
    Rainer Weikusat, Dec 7, 2011
    #4
  5. Krzysztof Poc

    Ken Butler Guest

    On Wed, 7 Dec 2011, Rainer Weikusat wrote:

    > Ken Butler <> writes:
    >> On Wed, 7 Dec 2011, Ben Morrow wrote:
    >>
    >>> $tree->{singers}{album}[0]{children}{child}[0]
    >>>
    >>> (the first is obviously necessary so Perl knows you're talking about a
    >>> hashref in $tree rather than an element of the hash %tree).
    >>>
    >>>> My question is how can I do my task in a loop. I tried to combine both
    >>>> "foreach" and "exists" functions but I failed.
    >>>
    >>> Here's a hint:
    >>>
    >>> for my $album ( @{ $tree->{singers}{album} } ) {
    >>> ...
    >>> }
    >>>
    >>> The @{...} syntax is probably what you were missing. (Yes, we all know
    >>> it's ugly.) Start by (re-)reading the 'Using References' section of
    >>> perlreftut.

    >>
    >> This I don't understand. I thought the @{} turned a hash (ref) into an
    >> array, whose elements are alternately key, value, key, value,... so
    >> that iterating through the array would *not* simply pull out just the
    >> keys.

    >
    > But $tree->{singers}{album} isn't a hash reference its an array
    > reference. At least, your attempt at subscripting it strongly suggests
    > this.


    OK, missed that, thanks.
     
    Ken Butler, Dec 7, 2011
    #5
  6. On Dec 7, 11:10 pm, Ben Morrow <> wrote:
    > Quoth Ken Butler <>:
    >
    >
    >
    >
    >
    > > On Wed, 7 Dec 2011, Ben Morrow wrote:

    >
    > > >    $tree->{singers}{album}[0]{children}{child}[0]

    >
    > > > (the first is obviously necessary so Perl knows you're talking about a
    > > > hashref in $tree rather than an element of the hash %tree).

    >
    > > >> My question is how can I do my task in a loop. I tried to combine both
    > > >> "foreach" and "exists" functions but I failed.

    >
    > > > Here's a hint:

    >
    > > >    for my $album ( @{ $tree->{singers}{album} } ) {
    > > >        ...
    > > >    }

    >
    > > > The @{...} syntax is probably what you were missing. (Yes, we all know
    > > > it's ugly.) Start by (re-)reading the 'Using References' section of
    > > > perlreftut.

    >
    > > This I don't understand. I thought the @{} turned a hash (ref) into an
    > > array, whose elements are alternately key, value, key, value,... so that
    > > iterating through the array would *not* simply pull out just the keys.

    >
    > No, that's %{} in list context. @{} (in list context) turns an arrayref
    > into a list.
    >
    > > My code for the above would say something like

    >
    > > for my $album (keys %{$tree->{singers}{album}})

    >
    > Did you try this? I would expect a 'Not a HASH reference' error, which
    > would have given you some idea of what was wrong.
    >
    > Ben


    Great thanks for help to all of you. Finally Ben Marrow's hint works
    for me.
     
    Krzysztof Poc, Dec 8, 2011
    #6
  7. Krzysztof Poc

    Ken Butler Guest

    On Wed, 7 Dec 2011, Ben Morrow wrote:

    >
    > Quoth Ken Butler <>:


    >> My code for the above would say something like
    >>
    >> for my $album (keys %{$tree->{singers}{album}})

    >
    > Did you try this? I would expect a 'Not a HASH reference' error, which
    > would have given you some idea of what was wrong.


    Usually, I manage to follow the maxim of "read twice, post once". Here I
    managed to miss the [0] (after {album}) entirely, which of course makes
    all the difference.

    Had I received that error message, I would have stopped, asked myself "why
    on earth isn't it a hash reference, then?", scratched my head a few times,
    and then figured it out.

    So:

    for my $i (keys %{$x->{$y}}) {...}

    will get at $x->{$y}{$i}

    and

    for my $i (@{$x->{$y}}) {...}

    will get at $x->{$y}[$i]

    if I have it right now.


    Cheers,
    Ken.


    ..
     
    Ken Butler, Dec 9, 2011
    #7
  8. Krzysztof Poc

    Willem Guest

    Ken Butler wrote:
    ) So:
    )
    ) for my $i (keys %{$x->{$y}}) {...}
    )
    ) will get at $x->{$y}{$i}

    Correct.

    ) and
    )
    ) for my $i (@{$x->{$y}}) {...}
    )
    ) will get at $x->{$y}[$i]

    Not quite.
    That will make $i be each of the *values* of $x->{$y}[...]

    The following are equivalent:

    for my $i (keys %{$x->{$y}})
    and
    for my $i (0 .. $#{$x->{$y}})

    As are the following:

    for my $v (values ${$x->{$y}})
    and
    for my $v (@{$x->{$y}})


    Can you see why ?


    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
     
    Willem, Dec 10, 2011
    #8
  9. Krzysztof Poc

    Ken Butler Guest

    On Sat, 10 Dec 2011, Willem wrote:

    > Ken Butler wrote:
    > ) So:
    > )
    > ) for my $i (keys %{$x->{$y}}) {...}
    > )
    > ) will get at $x->{$y}{$i}
    >
    > Correct.
    >
    > ) and
    > )
    > ) for my $i (@{$x->{$y}}) {...}
    > )
    > ) will get at $x->{$y}[$i]
    >
    > Not quite.
    > That will make $i be each of the *values* of $x->{$y}[...]


    Ah, in the same way that

    for my $i (@a) {...}

    gives you the *values* of @a,

    and

    for my $i (0..$#a) {...}

    gives you the *indices* of @a, so that $a[$i] is how you get at the value.

    > The following are equivalent:
    >
    > for my $i (keys %{$x->{$y}})
    > and
    > for my $i (0 .. $#{$x->{$y}})
    >
    > As are the following:
    >
    > for my $v (values ${$x->{$y}})
    > and
    > for my $v (@{$x->{$y}})
    >
    >
    > Can you see why ?


    Yep, I reckon I understand it now. In your two pairs of examples, $i takes
    the values of the keys of the hash and the indices of the array, and $v
    takes the values of the hash (rather transparently) and the values of the
    array.

    Cheers,
    Ken.
     
    Ken Butler, Dec 10, 2011
    #9
    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. navS
    Replies:
    3
    Views:
    526
    Ismo Salonen
    May 9, 2008
  2. carl
    Replies:
    5
    Views:
    2,424
    James Kanze
    Nov 25, 2009
  3. rp
    Replies:
    1
    Views:
    556
    red floyd
    Nov 10, 2011
  4. Depili
    Replies:
    5
    Views:
    144
    David Vallner
    Jan 13, 2006
  5. Steven Hirsch

    Iterating over a hash of hash of hashes

    Steven Hirsch, Aug 19, 2008, in forum: Ruby
    Replies:
    0
    Views:
    156
    Steven Hirsch
    Aug 19, 2008
Loading...

Share This Page