tags:

views:

69

answers:

2

I load the following YAML stream into a Perl's array and I want to traverse the array associated with Field2.

use YAML;

my @arr = Load(<<'...');
---
Field1: F1
Field2:
 - {Key: v1, Val: v2}
 - {Key: v3, Val: v4}
---
Field1: F2
Field2:
 - {Key: v5, Val: v6}
 - {Key: v7, Val: v8}
...

foreach (@arr) {
    @tmp = $_->{'Field2'};   
    print $#tmp; # why it says 0 when I have 2 elements?

    # Also why does the below loop not work? 
    foreach ($_->{'Field2'}) {
    print $_->{'Key'} . " -> " $_->{'Val'} . "\n";
 }
}

I appreciate any feedback. Thank you.

+5  A: 

Because you are not using references correctly. You may want to reread perldoc perlreftut and perldoc perlref.

#!/usr/bin/perl

use strict;
use warnings;

use YAML;

my @arr = Load(<<'...');
---
Field1: F1
Field2:
 - {Key: v1, Val: v2}
 - {Key: v3, Val: v4}
---
Field1: F2
Field2:
 - {Key: v5, Val: v6}
 - {Key: v7, Val: v8}
...

for my $record (@arr) {
     print "$record->{Field1}:\n";
     for my $subrecord (@{$record->{Field2}}) {
         print "\t$subrecord->{Key} = $subrecord->{Val}\n";
     }
}
Chas. Owens
You did not address the part where Martin inquires about the count of hashref values for the `Field2` keys.
daxim
@daxim The links address that and other concerns related to references.
Chas. Owens
+1  A: 

You need to do some exercises with data structures and references. This works:

use 5.010;
use strict;
use warnings FATAL => 'all';

use YAML qw(Load);

my @structs = Load(<<'...');
---
Field1: F1
Field2:
 - {Key: v1, Val: v2}
 - {Key: v3, Val: v4}
---
Field1: F2
Field2:
 - {Key: v5, Val: v6}
 - {Key: v7, Val: v8}
...

# (
#     {
#         Field1 => 'F1',
#         Field2 => [
#             {
#                 Key => 'v1',
#                 Val => 'v2'
#             },
#             {
#                 Key => 'v3',
#                 Val => 'v4'
#             }
#         ]
#     },
#     {
#         Field1 => 'F2',
#         Field2 => [
#             {
#                 Key => 'v5',
#                 Val => 'v6'
#             },
#             {
#                 Key => 'v7',
#                 Val => 'v8'
#             }
#         ]
#     }
# )

foreach (@structs) {
    my $f2_aref = $_->{'Field2'};
    print scalar @{ $f2_aref }; # 2

    foreach (@{ $f2_aref }) {
        say sprintf '%s -> %s', $_->{'Key'}, $_->{'Val'};
    }

#     v1 -> v2
#     v3 -> v4
#     v5 -> v6
#     v7 -> v8
}
daxim
Why are you using `sprintf` instead of string interpolation? Also, this code won't run. You need to use the `feature` pragma or say `use 5.12;` (in which case you don't need the `use strict;` anymore) to use the `say` function.
Chas. Owens
@Chas. Owens: I think you mean `use 5.012;` sprintf often makes for clearer code than interpolation.
ysth
Because it's (subjective) better style. Some references won't interpolate (easily, that is, yes I know the ref-deref trick), and [it's really dumb to waste any brain power](http://en.wikipedia.org/wiki/Don't_Make_Me_Think) to decide such trivialities whether I can use it or not, when a construct such as `sprintf`, OTOH, always works. ― I added `use 5.010;`. Now kindly remove your downvote.
daxim
@ysth Yes, I do.
Chas. Owens
@daxim I didn't downvote you. I don't normally downvote people; I have only downvoted 19 times in the last year and a half. Nothing you did warranted a downvote in my opinion (I save them for dangerous or bad advice). The only time I have found interpolation to not work is when you are calling a method (which is not surprising since functions don't interpolate), do you have any examples where a dereference wouldn't interpolating? I honestly can't think of a situation where that could happen.
Chas. Owens
@Chas: `say` is enabled with feature bundle ":5.10" and is part of Perl release 5.10. http://search.cpan.org/~rgarcia/perl-5.10.0/pod/perl5100delta.pod
drewk
@drewk Yes, but who is using 5.10? Everybody I know is using 5.8.* because they aren't willing to upgrade or 5.12 because they are.
Chas. Owens
@drewk: automatic application of strict isn't part of `use 5.010;`
ysth
@Chas: Perl 5.10 is the OS default install on OS X Snow Leopard and Ubuntu 10.04 so it is not uncommon. ie, if the user of those OS takes the default they will have Perl 5.10. I run 5.10 on OS X and a manual upgrade to 5.12 on Ubuntu.
drewk
@ysth: Thanks for the clarification. `say` is what I was focusing on, but I do like the new autostrict.
drewk
@drewk Again, who uses the system version of Perl? That stuff is toxic. I use OS X as well and am running 5.12. Take a look at [perlbrew](http://search.cpan.org/dist/App-perlbrew/lib/App/perlbrew.pm). It and [cpanminus](http://search.cpan.org/dist/App-cpanminus/lib/App/cpanminus.pm) incredibly easy to manage a custom build. When I say I am running 5.12, I really mean I am running 5.10.1, 5.12.1, and 5.13.4 (all managed by perlbrew), but I use 5.12 the most.
Chas. Owens
@Chas: Thanks! I will take a look at those links. Of course, "who uses the system version of Perl?" Probably 98.66% of the users of those systems. Users don't know, don't care, don't upgrade. Well, me as an occasional Perl user! When you say "toxic" is there specific reasons the system version of Perl should not be used?
drewk
@drewk System versions of Perl and CPAN installs should not be mixed, or [breakage occurs](http://bulknews.typepad.com/blog/2009/02/mac-os-x-security-update-2009001-breaks-perl-cpan.html). You have two options: only use your system (YUM, APT, whatever) to install Perl 5 modules from vendor approved repositories (note, there is no Apple approved method of installing modules on OS X) or roll your own Perl 5 install (e.g. perlbrew). The later is the safer choice. The system Perl is there for the system. You install and upgrade its modules at your own peril.
Chas. Owens
@Chas: "You install and upgrade [the system] modules at your own peril" The reason, of course, I never upgraded because I never dug into the details of it being OK and compatible with Apple's OS upgrade scheme. I also have been a reluctant CPAN installer for similar reasons. I get it (and this is news to me) perlbrew is for USER perl use and development and you just leave the system Perl install absolutely alone. You, the user, are free to take risks on Perl upgrades that you should not take with the system image of Perl since it is a vital component. Got it. Thanks. I will try this.
drewk