iterating through a hash map

K

Krzysztof Poc

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

Krzysztof Poc

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

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

Ken Butler

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

Rainer Weikusat

Ken Butler said:
$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.
 
K

Ken Butler

Ken Butler said:
$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.
 
K

Krzysztof Poc

Quoth Ken Butler <[email protected]>:




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

Ken Butler

Quoth Ken Butler <[email protected]>:

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.


..
 
W

Willem

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
 
K

Ken Butler

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.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top