complex data structure | | |
I've created a beast! Here is my data structure:
$VAR1 = 'bunkers';
$VAR2 = {
'items' => [
\[
{
'archie' => 'conservative'
}
],
\[
{
'meathead' => 'liberal'
}
]
]
};
$VAR3 = 'simpsons';
$VAR4 = {
'items' => [
\[
{
'haha' => 'nelson munce'
}
],
\[
{
'whoohoo' => 'homer simpson'
}
]
]
};
How do I access the hash key value pairs? This fails at runtime:
(Not a HASH reference at haha line 22.)
foreach $key (keys %hash){
print "[".$key."]\n";
for $who (@{$hash{$key}{items}}){
foreach $item (keys %{$who}){
print $item . " => " . $who->{$item} . "\n";
}
}
}
TIA,
Jeff | | | | re: complex data structure
Jeff wrote:
[color=blue]
> I've created a beast! Here is my data structure:
>
> $VAR1 = 'bunkers';
> $VAR2 = {
> 'items' => [
> \[
> {
> 'archie' => 'conservative'
> }
> ],
> \[
> {
> 'meathead' => 'liberal'
> }
> ]
> ]
> };
> $VAR3 = 'simpsons';
> $VAR4 = {
> 'items' => [
> \[
> {
> 'haha' => 'nelson munce'
> }
> ],
> \[
> {
> 'whoohoo' => 'homer simpson'
> }
> ]
> ]
> };
>
> How do I access the hash key value pairs? This fails at runtime:
> (Not a HASH reference at haha line 22.)
>
> foreach $key (keys %hash){
> print "[".$key."]\n";
> for $who (@{$hash{$key}{items}}){
> foreach $item (keys %{$who}){
> print $item . " => " . $who->{$item} . "\n";
> }
> }
> }[/color]
....[color=blue]
> Jeff[/color]
That *is* a beast of a structure. I'll take your word for it that that
is really the structure you want (scalar references to array references
included). I also assume that your *original* data structure was a hash
containing $VAR1 through $VAR4 as keys/values, and that you didn't
properly dump a reference to that outside hash, but rather independently
dumped the keys/values to that hash. If so, here you go...
use warnings; #let Perl help you all it can
use strict; #let Perl help you all it can
my $VAR1 = 'bunkers';
my $VAR2 = {
'items' => [
\[
{
'archie' => 'conservative'
}
],
\[
{
'meathead' => 'liberal'
}
]
]
};
my $VAR3 = 'simpsons';
my $VAR4 = {
'items' => [
\[
{
'haha' => 'nelson munce'
}
],
\[
{
'whoohoo' => 'homer simpson'
}
]
]
};
#reconstitute assumed original structure:
my %hash=($VAR1,$VAR2,$VAR3,$VAR4);
=item
How do I access the hash key value pairs? This fails at runtime:
(Not a HASH reference at haha line 22.)
=cut
foreach my $key (keys %hash){
print "[".$key."]\n";
for my $who (@{$hash{$key}->{items}}){
foreach my $item (keys %{${$$who}[0]}){
print $item . " => " . $$who->[0]->{$item} . "\n";
}
}
}
HTH. You didn't show enough of your intended data structure for me to
know if you actually intend to have one-element arrays where I show them
in the code -- if they will actually have more than one element, you
will need to introduce another foreach loop to iterate over them. My
guess this isn't the data structure you really want.
--
Bob Walton
Email: http://bwalton.com/cgi-bin/emailbob.pl | | | | re: complex data structure
Bob Walton wrote:[color=blue]
> Jeff wrote:
>[color=green]
>> I've created a beast! Here is my data structure:
>>
>> $VAR1 = 'bunkers';
>> $VAR2 = {
>> 'items' => [
>> \[
>> {
>> 'archie' => 'conservative'
>> }
>> ],
>> \[
>> {
>> 'meathead' => 'liberal'
>> }
>> ]
>> ]
>> };
>> $VAR3 = 'simpsons';
>> $VAR4 = {
>> 'items' => [
>> \[
>> {
>> 'haha' => 'nelson munce'
>> }
>> ],
>> \[
>> {
>> 'whoohoo' => 'homer simpson'
>> }
>> ]
>> ]
>> };
>>
>> How do I access the hash key value pairs? This fails at runtime:
>> (Not a HASH reference at haha line 22.)
>>
>> foreach $key (keys %hash){
>> print "[".$key."]\n";
>> for $who (@{$hash{$key}{items}}){
>> foreach $item (keys %{$who}){
>> print $item . " => " . $who->{$item} . "\n";
>> }
>> }
>> }[/color]
>
> ...
>[color=green]
>> Jeff[/color]
>
>
> That *is* a beast of a structure. I'll take your word for it that that
> is really the structure you want (scalar references to array references
> included). I also assume that your *original* data structure was a hash
> containing $VAR1 through $VAR4 as keys/values, and that you didn't
> properly dump a reference to that outside hash, but rather independently
> dumped the keys/values to that hash. If so, here you go...
>
> use warnings; #let Perl help you all it can
> use strict; #let Perl help you all it can
> my $VAR1 = 'bunkers';
> my $VAR2 = {
> 'items' => [
> \[
> {
> 'archie' => 'conservative'
> }
> ],
> \[
> {
> 'meathead' => 'liberal'
> }
> ]
> ]
> };
> my $VAR3 = 'simpsons';
> my $VAR4 = {
> 'items' => [
> \[
> {
> 'haha' => 'nelson munce'
> }
> ],
> \[
> {
> 'whoohoo' => 'homer simpson'
> }
> ]
> ]
> };
> #reconstitute assumed original structure:
> my %hash=($VAR1,$VAR2,$VAR3,$VAR4);
> =item
> How do I access the hash key value pairs? This fails at runtime:
> (Not a HASH reference at haha line 22.)
> =cut
> foreach my $key (keys %hash){
> print "[".$key."]\n";
> for my $who (@{$hash{$key}->{items}}){
> foreach my $item (keys %{${$$who}[0]}){
> print $item . " => " . $$who->[0]->{$item} . "\n";
> }
> }
> }
>
> HTH. You didn't show enough of your intended data structure for me to
> know if you actually intend to have one-element arrays where I show them
> in the code -- if they will actually have more than one element, you
> will need to introduce another foreach loop to iterate over them. My
> guess this isn't the data structure you really want.
>[/color]
I'm certainly open to suggestions. Here is the method that creates the
hash:
sub getHashes()
{
my $this = shift;
my ($sep,$bad_programmer) = @_;
my (%hash, $hash);
my $lines = "";
my (@list, @cols);
my ($left,$right);
my ($prefix, $items);
if(open(FILE, "<" . $this->{"file"})){
flock(FILE, $LOCK_EX);
while(<FILE>){
next if /^$/;
next if /^\s*#/;
$lines .= $_;
}
flock(FILE, $LOCK_UN);
close(FILE);
}
$prefix = 'default';
$items = 'items';
foreach my $thing ( split( /\n/, $lines ) ){
if($thing =~ m/^\[([^\]]+)\]$/){
$prefix = $1;
print "PREFIX: $prefix\n";
next;
}
($left,$right) = split( /$sep/, $thing );
# Trim begnining and trailing whitespace
$left=~s/^\s+//;
$right=~s/^\s+//;
$left=~s/\s+$//;
$right=~s/\s+$//;
#$hash{$prefix}{$items} = [{ $left => $right, }];
push(@{$hash{$prefix}{$items}}, \[{ $left => $right, }]);
}
return %hash;
}
I had really wanted to push arrays (not refs) on $hash{$prefix}{$items}
Jeff | | | | re: complex data structure
> foreach $item (keys %{$who}){
The major problem in the above is that $who is neither a Simpsons reference
nor a Bunkers reference, it's a Dr. Seuss reference.
Okay, seriously... Like the error says, $who is not a hash ref, it's an
array ref, so the above should be:
foreach $item (@{$who}) {
Also, the array referred to by $who contains two items - each is a reference
to a reference (not a typo - note the backslash in the Data::Dumper output)
to an array. The inner array contains a single item, which is a reference
to a hash containing a single item.
To work with the code as given, your data structure would need to look in
part like this:
$VAR4 = {
'items' => {
'haha' => 'nelson munce',
'whoohoo' => 'homer simpson'
}
};
If the data is correct as given, then the code will need to be restructured
to correctly deal with the additional layers of array references.
To help deal with these issues, I suggest reading 'perldoc
perlreftut' (References Tutorial), 'perldoc perldsc' (Data Structures
Cookbook), and 'perldoc perllol' (Lists of Lists), in that order.
sherm--
--
Cocoa programming in Perl: http://camelbones.sourceforge.net
Hire me! My resume: http://www.dot-app.org | | | | re: complex data structure
Jeff wrote:
[color=blue]
> Bob Walton wrote:
>[color=green]
>> Jeff wrote:[/color][/color]
....[color=blue]
> I'm certainly open to suggestions. Here is the method that creates the
> hash:
>
> sub getHashes()
> {
> my $this = shift;
> my ($sep,$bad_programmer) = @_;
> my (%hash, $hash);
> my $lines = "";
> my (@list, @cols);
> my ($left,$right);
> my ($prefix, $items);
>
> if(open(FILE, "<" . $this->{"file"})){
> flock(FILE, $LOCK_EX);
> while(<FILE>){
> next if /^$/;
> next if /^\s*#/;
> $lines .= $_;
> }
> flock(FILE, $LOCK_UN);
> close(FILE);
> }[/color]
else { #you don't really want to continue if the open failed
die "file open failed for $this->{file}"
}
[color=blue]
>
> $prefix = 'default';
> $items = 'items';
> foreach my $thing ( split( /\n/, $lines ) ){
> if($thing =~ m/^\[([^\]]+)\]$/){
> $prefix = $1;
> print "PREFIX: $prefix\n";
> next;
> }
> ($left,$right) = split( /$sep/, $thing );
> # Trim begnining and trailing whitespace
> $left=~s/^\s+//;
> $right=~s/^\s+//;
> $left=~s/\s+$//;
> $right=~s/\s+$//;
> #$hash{$prefix}{$items} = [{ $left => $right, }];[/color]
In the above (if it weren't commented out), you would be storing a
reference to a one element anonymous array, the contents of which are a
reference to an anonymous one-key hash. If you just have two things to
store, just put them in the array: = [$left,$right]; It just garbages
things up to have one-element arrays and one-key hashes.
[color=blue]
> push(@{$hash{$prefix}{$items}}, \[{ $left => $right, }]);[/color]
Here, you are pushing a reference to a reference to a one-element
anonymous array, the element of which is a reference to a one-key
anonymous hash. That's *way* out of control: [untested]
push(@{$hash{$prefix}{%items}},[$left,$right];
should accomplish the same data storage task, but in a much cleaner fashion.
Note that
$q=[1,2,3,4];
stores a reference to an anonymous 4-element array into scalar variable
$q. It is not necessary or desirable to do:
$q=\[1,2,3,4];
which stores a reference to a reference to an anonymous 4-element array
in $q.
[color=blue]
> }
> return %hash;
> }
>
> I had really wanted to push arrays (not refs) on $hash{$prefix}{$items}[/color]
I'm not sure what your are trying to say in that statement. A hash
element (or an array element for that matter) can only hold one sort of
thing: a scalar. Therefore, you can't "push arrays on $hash{...}" --
but you *can* place a *reference* to an array in a hash as a hash
element value.
Check out:
perldoc perldsc
perldoc perllol
perldoc perlref
etc.
[color=blue]
> Jeff[/color]
--
Bob Walton
Email: http://bwalton.com/cgi-bin/emailbob.pl | | | | re: complex data structure
Bob Walton wrote:[color=blue]
> Jeff wrote:
>[color=green]
>> Bob Walton wrote:
>>[color=darkred]
>>> Jeff wrote:[/color][/color]
>
> ...
>[color=green]
>> I'm certainly open to suggestions. Here is the method that creates the
>> hash:
>>
>> sub getHashes()
>> {
>> my $this = shift;
>> my ($sep,$bad_programmer) = @_;
>> my (%hash, $hash);
>> my $lines = "";
>> my (@list, @cols);
>> my ($left,$right);
>> my ($prefix, $items);
>>
>> if(open(FILE, "<" . $this->{"file"})){
>> flock(FILE, $LOCK_EX);
>> while(<FILE>){
>> next if /^$/;
>> next if /^\s*#/;
>> $lines .= $_;
>> }
>> flock(FILE, $LOCK_UN);
>> close(FILE);
>> }[/color]
>
>
>
> else { #you don't really want to continue if the open failed
> die "file open failed for $this->{file}"
> }
>
>[color=green]
>>
>> $prefix = 'default';
>> $items = 'items';
>> foreach my $thing ( split( /\n/, $lines ) ){
>> if($thing =~ m/^\[([^\]]+)\]$/){
>> $prefix = $1;
>> print "PREFIX: $prefix\n";
>> next;
>> }
>> ($left,$right) = split( /$sep/, $thing );
>> # Trim begnining and trailing whitespace
>> $left=~s/^\s+//;
>> $right=~s/^\s+//;
>> $left=~s/\s+$//;
>> $right=~s/\s+$//;
>> #$hash{$prefix}{$items} = [{ $left => $right, }];[/color]
>
>
>
> In the above (if it weren't commented out), you would be storing a
> reference to a one element anonymous array, the contents of which are a
> reference to an anonymous one-key hash. If you just have two things to
> store, just put them in the array: = [$left,$right]; It just garbages
> things up to have one-element arrays and one-key hashes.
>
>[color=green]
>> push(@{$hash{$prefix}{$items}}, \[{ $left => $right, }]);[/color]
>
>
>
> Here, you are pushing a reference to a reference to a one-element
> anonymous array, the element of which is a reference to a one-key
> anonymous hash. That's *way* out of control: [untested]
>
> push(@{$hash{$prefix}{%items}},[$left,$right];
>
> should accomplish the same data storage task, but in a much cleaner
> fashion.
>
> Note that
>
> $q=[1,2,3,4];
>
> stores a reference to an anonymous 4-element array into scalar variable
> $q. It is not necessary or desirable to do:
>
> $q=\[1,2,3,4];
>
> which stores a reference to a reference to an anonymous 4-element array
> in $q.
>
>[color=green]
>> }
>> return %hash;
>> }
>>
>> I had really wanted to push arrays (not refs) on $hash{$prefix}{$items}[/color]
>
>
>
> I'm not sure what your are trying to say in that statement. A hash
> element (or an array element for that matter) can only hold one sort of
> thing: a scalar. Therefore, you can't "push arrays on $hash{...}" --
> but you *can* place a *reference* to an array in a hash as a hash
> element value.
>
> Check out:
>
> perldoc perldsc
> perldoc perllol
> perldoc perlref
>
> etc.
>
>[/color]
Thanks. That helped considerably. This is closer to what I wanted:
sub getHashes()
{
my $this = shift;
my ($sep,$bad_programmer) = @_;
my (%hash, $rec);
my $lines = "";
my ($prefix);
if(open(FILE, "<" . $this->{"file"})){
flock(FILE, $LOCK_EX);
while(<FILE>){
next if /^$/;
next if /^\s*#/;
$lines .= $_;
}
flock(FILE, $LOCK_UN);
close(FILE);
}
$prefix = 'default';
$rec = {};
$hash{$prefix} = $rec;
foreach my $thing (split(/\n/, $lines)){
$thing=~s/^\s+//; # trim leading white space
$thing=~s/\s+$//; # trim trailing white space
if($thing =~ m/^\[([^\]]+)\]$/){
$prefix = $1;
$rec = {};
$hash{$prefix} = $rec;
next;
} else {
my($key, $value) = split /$sep/, $thing;
$key=~s/^\s+//;
$value=~s/^\s+//;
$key=~s/\s+$//;
$value=~s/\s+$//;
$rec->{$key} = $value;
}
}
return %hash;
} |  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,449 network members.
|