[Melbourne-pm] Hash Containing Array
Jacinta Richardson
jarich at perltraining.com.au
Sat Mar 21 18:48:26 PDT 2009
I've expanded the code a little to include some scaffolding, so I'm
working with:
##########################################
package Foo;
use strict;
use warnings;
sub new {
my $class = shift;
my $self = {};
$self->{_DATASET} = undef;
$self->{_RULE} = undef;
$self->{_PRIVILEGE} = undef;
$self->{_ACC_VIA_RULE} = {};
$self->{_ACC_VIA_PRIV} = [];
$self->{_CAN_UPDATE_RULE} = [];
bless( $self, $class );
return $self;
}
sub set_acc_via_rule {
my $self = shift;
my $key = shift;
my @val = @_;
foreach my $val (@val) {
unshift @{ $self->{_ACC_VIA_RULE}{$key} }, $val;
}
return;
}
sub get_back_keys {
my $self = shift;
my ( $key, $value );
while ( my ( $key, $value ) = each( $self->{_ACC_VIA_RULE} ) ) {
unshift @keys, $key;
}
return @keys;
}
package main;
use strict;
use warnings;
use Data::Dumper;
my $foo = Foo->new();
$foo->set_acc_via_rule("bar", (1..10));
$foo->set_acc_via_rule("baz", ('a'..'j'));
print Dumper $foo;
##########################################
This still yields the same error you were getting:
Type of arg 1 to each must be hash (not hash element) at test.pl line
31, near "} ) "
and also:
Global symbol "@keys" requires explicit package name at test.pl line 32.
Global symbol "@keys" requires explicit package name at test.pl line 34.
because you never declare @keys in your get_back_keys method.
If we comment out get_back_keys and run this we get the following
Data::Dumper structure:
$VAR1 = bless( {
'_RULE' => undef,
'_CAN_UPDATE_RULE' => [],
'_PRIVILEGE' => undef,
'_ACC_VIA_PRIV' => [],
'_ACC_VIA_RULE' => {
'bar' => [
10,
9,
8,
7,
6,
5,
4,
3,
2,
1
],
'baz' => [
'j',
'i',
'h',
'g',
'f',
'e',
'd',
'c',
'b',
'a'
]
},
'_DATASET' => undef
}, 'Foo' );
Now I'm guessing from your code that what you want is a method that just
returns 'bar' and 'baz'. For this, we don't need to use each, because
we don't care about the values, only the keys. Thus we can write:
sub get_back_keys {
my $self = shift;
my @keys;
foreach my $key ( keys %{ $self->{_ACC_VIA_RULE} } ) {
unshift @keys, $key;
}
return @keys;
}
The main mistake you were making was not telling Perl to dereference
your hash. When you wrote:
while ( my ( $key, $value ) = each( $self->{_ACC_VIA_RULE} ) )
you were passing a hash _reference_ to each when each expected a hash.
To dereference this into a hash we need to change:
$self->{_ACC_VIA_RULE}
to:
%{ $self->{_ACC_VIA_RULE} }
which is what I did so that I passed the hash to keys, not the hash
reference. Making this small change in your code (and adding "my
@keys;" makes your code work).
You are using "unshift" a lot, where most people would use "push".
unshift adds something to the start of the array, whereas push adds it
to the end of the array. The syntax is the same. I realise this might
be a coding requirement, but if not, it's worth being aware that most
people will expect to see push rather than unshift. The following two
snippets achieve the same result:
foreach my $val (@val) {
unshift @{ $self->{_ACC_VIA_RULE}{$key} }, $val;
}
foreach my $val (reverse @val) {
push @{ $self->{_ACC_VIA_RULE}{$key} }, $val;
}
By all means use unshift if it does what you require!
All the best,
Jacinta
More information about the Melbourne-pm
mailing list