Popcorn Dave has asked for the wisdom of the Perl Monks concerning the following question:

Fellow monks I come to you again for guidance.

I am stuck with a particular piece of Perl and have tried everything I can think of to solve the problem.

This is the test code I've been playing with:

#!/usr/bin/perl -w $table={}; for $i (1..10){ $table{$i} = $i}; for $i (1..10){ if ($i%2==0){$table{$i}{shape}='rect'} else {$table{$i}{shape}='circle'} $table{$i}{coords} = [0,1,2,3,4,5,6,7,8,9]; } foreach $key ( keys %table ){ print "Key $key Value $table{$key}\n"; print "Shape $table{$key}{shape}\n"; foreach(@{$table{$key}{coords}}){print "$table{$key}{co +ords}[$_]"}; print "\n"; };

My problem lies in the fact that I want to be able to take a slice of said array. I'd rather be able to do something along the lines of $table{$key}{coords}[0,3] for example to get just the first 4 elements of said array in the hash.

Is this only possible by running a loop over this array?

Thanks in advance!

Replies are listed 'Best First'.
(jeffa) Re: Correct syntax to access an array slice within a hash within a hash
by jeffa (Bishop) on May 07, 2002 at 23:42 UTC
    Actually, you have more than one problem. The first is not using strict. The second is that you define your hash as a hash reference, but try to use at as a hash. But why are you using index numbers as keys for a hash? Wouldn't an array be better? Yes. An array of hash references as a matter of fact - a list of hashes (LoH):
    use strict; use Data::Dumper; my @shape; for (0..9) { unless ($_ % 2) { $shape[$_]->{shape} = 'rect' } else { $shape[$_]->{shape} = 'circle' } $shape[$_]->{coords} = [0,1,2,3,4,5,6,7,8,9]; } # what does it look like now? print Dumper \@shape; # and to get that slice: for (0..$#shape) { print "shape $_ is a ", $shape[$_]->{shape}, " (", join(',',@{$shape[$_]->{coords}}[0..3]), ")\n"; }
    Hope this helps. Note the use of Data::Dumper - always use it when you are molding your data structures. It is a true life saver. ;)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: Correct syntax to access an array slice within a hash within a hash
by broquaint (Abbot) on May 07, 2002 at 23:31 UTC
    Dereference that suckah
    my $table = { foo => { bar => [qw(one two three four five)] } }; print join(" - ", @{$table->{foo}->{bar}}[2..4]); __output__ three - four - five
    More info at perlref
    HTH

    _________
    broquaint

Re: Correct syntax to access an array slice within a hash within a hash
by snowcrash (Friar) on May 07, 2002 at 23:42 UTC
    Hi! Well, basically you want @{$table{$key}{coords}}[0,3] to get your slice.
    you version ($table{$key}{coors}[0,3]) just uses the list 0,3 in a scalar context (i.e. the last element) and so only fetches the value indexed by 3.

    a few other points:
  • you use the scalar variable $table in the beginning, later you just use the hash %table.
  • why do you set the value of each hash entry to the same integer as the key? you overwrite that later with a reference to another hash anyway.
  • most important point: use strict; and you would have noticed the other points i've addressed above ;)

    all in all i'd have done something like this:
    #!/usr/bin/perl -w use strict; my %table; for my $i (1..10) { $table{$i} = { shape => $i % 2 ? 'circle' : 'rect', coords => [0,1,2,3,4,5,6,7,8,9] } } foreach my $key (keys %table) { print "Key $key Value $table{$key}\n", "Shape $table{$key}{shape}\n", join(",", @{$table{$key}{coords}}[0,3]), "\n"; }

    snowcrash
slice of ( ref of HoH dereferenced as array )
by particle (Vicar) on May 08, 2002 at 00:05 UTC
    okay, Popcorn Dave, here's a little example, with comments. it's a little different from your example, but i think you can follow my example. if you're attempting data structures this complex, i hope you've read perlref, perlreftut, and perldsc.

    i've used strict: don't code without it. it offers protection from many problems you might encounter during development.

    #!/usr/bin/perl -w use strict; ## constants: i don't like 'use constant MAX => 3;', so... sub MAX() { 3 } sub SLICE() { 0 .. 1 } ## create empty hash reference ## ref to hash my $table_ref = {}; ## create some empty hashes ## ref to hash of hashes $table_ref->{$_} = () for( 0 .. MAX ); for( 0 .. MAX ) { if( $_ % 2 ) ## ref to hash of hashes holds scalar value { $table_ref->{$_}{shape} = 'rect' } else ## ref to hash of hashes holds scalar value { $table_ref->{$_}{shape} = 'circle' } ## ref to hash of hashes dereferenced as array, assign list @{ $table_ref->{$_}{coords} } = ( 0 .. MAX ); } for( sort keys %{ $table_ref } ) { print "Key: $_ Value: $table_ref->{$_}\n"; print "Shape $table_ref->{$_}{shape}\n"; ## ref to hash of hashes dereferenced as array, grab a slice print $_ for( @{ $table_ref->{$_}{coords} }[ SLICE ] ); print "\n"; }

    ~Particle *accelerates*

Re(Amel): Correct syntax to access an array slice within a hash within a hash
by dsb (Chaplain) on May 08, 2002 at 01:37 UTC
    Just as a sidenote to the advice already given by the others, be sure to note the use of @ to do the slice. EVEN WHEN IT'S A HASH SLICE.

    This is because technically, the slice is a list, and in Perl we use @ to indicate a list.

    A short example:

    # array slice @arr = qw(zero one two three); @arr[1,2] = (2,3) # hash slice %hash = ( one => 1, two => 2, three => 3, four => 4, ); @hash{'two','three'} = qw(two three);
    This is done without references, so be sure to dereference your hash ref in your code.

    Hope that helps.




    Amel
    This is my cool %SIG
Re: Correct syntax to access an array slice within a hash within a hash
by Popcorn Dave (Abbot) on May 08, 2002 at 05:24 UTC
    Just a quick thanks to all who offered replies. I really appreciate it!

    As far as that bit of code, yes I know it didn't have use strict there - it was simply test code, nothing more.

    I'm writing an image map program in Perl/Tk and my structure is a hash with a hash and an array.

    I did initially try the array structure as was pointed out as I was indexing by integer but ran in to difficulties with it and settled on the hash.

    Hopefully I will have the bugger finished here in the next day or two and will post it to Cool Uses for Perl.

    Again, thanks for all the help!