Hashes of Records -- who's smarter than me?

T

timdavis919

Hashes of Records -- who's smarter than me?

I'm hoping that someone who is smarter than me can solve this problem.
It shouldn't be hard -- I suspect I'm doing something obvious and
stupid, but I just can't see it.

I'm trying to create a hash of records, but the contents of all the
records in the hash seem to get overwritten by the contents of the
last record.

I wrote the simplified program below to demonstrate the problem.

In this simplified program I want to create three records (called
widgets) and assign them various characteristics (colors, powers,
etc.) by looping through arrays of those characteristics.

In the example below, I create a widget with name "thingy" color
"red" and power "hop". Then I put it into a hash of records
keyed by name and make sure I can read it out OK. Everything
seems to work.

Leaving out the looping for now, I just assign a new name and some
new characteristics to the record variable and write this second
record to the hash. The values from the second record (a blue
doodad that can skip) seem to overwrite the values in the first
record in the hash. So, although I put in a red thingy that can hop
and a blue doodad that can skip, I end up with two blue doodads --
one of which is still associatd with the hash key for the red thingy.

If anyone can see what the heck I'm doing wrong here, I would be the
happiest guy on the planet -- at least until I realize how embarrassing
my doubtlessly dumb mistake is...

-----------------------------------------------------------------------
CODE BEGINS HERE
-----------------------------------------------------------------------
#!/usr/local/bin/perl

use strict;

my @array_of_strings;
my @AoA_strings;
$AoA_strings[0] = [ @array_of_strings ];

my $widget = {
name => "",
colors => [@array_of_strings],
powers => [@AoA_strings],
};

my %hash_of_widgets;

my @allnames = ("thingy", "doodad", "whatzit");
my @allcolors = ("red", "blue", "green");
my @allpowers = (
["hop", "skip", "jump"],
["nip", "bite", "decapitate"],
);

# Create a thingy that is red and can hop
$widget->{name} = $allnames[0];
$widget->{colors}[0] = $allcolors[0];
$widget->{powers}[0][0] = $allpowers[0][0];

print "First, we make a $widget->{name} that is $widget->{colors}[0]
and can $widget->{powers}[0][0] \n\n";

#Put the red hopping thingy in the hash
$hash_of_widgets {$widget->{name}} = $widget;

print "Second, when we put it in the hash, we have there:\n";

for my $key (sort keys %hash_of_widgets)
{
print " for the hash key $key: a $hash_of_widgets{$key}->{name} that
is $hash_of_widgets{$key}->{colors}[0] and can
$hash_of_widgets{$key}->{powers}[0][0] \n";
}
print "\n";

# Create a doodad that is blue and can skip
$widget->{name} = $allnames[1];
$widget->{colors}[0] = $allcolors[1];
$widget->{powers}[0][0] = $allpowers[0][1];

print "Third, we make a $widget->{name} that is $widget->{colors}[0]
and can $widget->{powers}[0][0] \n\n";

$hash_of_widgets {$widget->{name}} = $widget;

print "Fourth, when we put him in the hash we have:\n";

for my $key (sort keys %hash_of_widgets)
{
print " for the hash key $key: a $hash_of_widgets{$key}->{name} that
is $hash_of_widgets{$key}->{colors}[0] and can
$hash_of_widgets{$key}->{powers}[0][0] \n";
}
 
G

gantenapalli

Hi buddy,

your have one $widget and you are over-writing it time and again.

Solution:
either have a $widget1,$widget2 or
have a method widget that take there initialization values
as arguments and returns a reference to a hash(after initializing it
with values) to suit your purpous.

Cheers,
Srini





Hashes of Records -- who's smarter than me?

I'm hoping that someone who is smarter than me can solve this problem.
It shouldn't be hard -- I suspect I'm doing something obvious and
stupid, but I just can't see it.

I'm trying to create a hash of records, but the contents of all the
records in the hash seem to get overwritten by the contents of the
last record.

I wrote the simplified program below to demonstrate the problem.

In this simplified program I want to create three records (called
widgets) and assign them various characteristics (colors, powers,
etc.) by looping through arrays of those characteristics.

In the example below, I create a widget with name "thingy" color
"red" and power "hop". Then I put it into a hash of records
keyed by name and make sure I can read it out OK. Everything
seems to work.

Leaving out the looping for now, I just assign a new name and some
new characteristics to the record variable and write this second
record to the hash. The values from the second record (a blue
doodad that can skip) seem to overwrite the values in the first
record in the hash. So, although I put in a red thingy that can hop
and a blue doodad that can skip, I end up with two blue doodads --
one of which is still associatd with the hash key for the red thingy.

If anyone can see what the heck I'm doing wrong here, I would be the
happiest guy on the planet -- at least until I realize how embarrassing
my doubtlessly dumb mistake is...

-----------------------------------------------------------------------
CODE BEGINS HERE
-----------------------------------------------------------------------
#!/usr/local/bin/perl

use strict;

my @array_of_strings;
my @AoA_strings;
$AoA_strings[0] = [ @array_of_strings ];

my $widget = {
name => "",
colors => [@array_of_strings],
powers => [@AoA_strings],
};

my %hash_of_widgets;

my @allnames = ("thingy", "doodad", "whatzit");
my @allcolors = ("red", "blue", "green");
my @allpowers = (
["hop", "skip", "jump"],
["nip", "bite", "decapitate"],
);

# Create a thingy that is red and can hop
$widget->{name} = $allnames[0];
$widget->{colors}[0] = $allcolors[0];
$widget->{powers}[0][0] = $allpowers[0][0];

print "First, we make a $widget->{name} that is $widget->{colors}[0]
and can $widget->{powers}[0][0] \n\n";

#Put the red hopping thingy in the hash
$hash_of_widgets {$widget->{name}} = $widget;

print "Second, when we put it in the hash, we have there:\n";

for my $key (sort keys %hash_of_widgets)
{
print " for the hash key $key: a $hash_of_widgets{$key}->{name} that
is $hash_of_widgets{$key}->{colors}[0] and can
$hash_of_widgets{$key}->{powers}[0][0] \n";
}
print "\n";

# Create a doodad that is blue and can skip
$widget->{name} = $allnames[1];
$widget->{colors}[0] = $allcolors[1];
$widget->{powers}[0][0] = $allpowers[0][1];

print "Third, we make a $widget->{name} that is $widget->{colors}[0]
and can $widget->{powers}[0][0] \n\n";

$hash_of_widgets {$widget->{name}} = $widget;

print "Fourth, when we put him in the hash we have:\n";

for my $key (sort keys %hash_of_widgets)
{
print " for the hash key $key: a $hash_of_widgets{$key}->{name} that
is $hash_of_widgets{$key}->{colors}[0] and can
$hash_of_widgets{$key}->{powers}[0][0] \n";
}
 
B

Brad Baxter

Hashes of Records -- who's smarter than me?

I'm hoping that someone who is smarter than me can solve this problem.
It shouldn't be hard -- I suspect I'm doing something obvious and
stupid, but I just can't see it.

I'm trying to create a hash of records, but the contents of all the
records in the hash seem to get overwritten by the contents of the
last record.
[snip]

Does this help?

#!/usr/local/bin/perl

use warnings;
use strict;
use Data::Dumper;
$Data::Dumper::Indent--;
$Data::Dumper::Terse++;

my %hash_of_widgets;

$hash_of_widgets{ thingy } = { color => 'red', power => 'hop' };
$hash_of_widgets{ doodad } = { color => 'blue', power => 'skip' };

print Dumper \%hash_of_widgets;
 
T

timdavis919

OK, maybe I'm missing something here. What's the point of Perl
implementing a non-homogenous data structure if you can't store the
contents of that data structure in another variable? If one is trying
to build a hierarchy of data structures the Perl record seems like a
dead end. That is, I can build up, for example: 1) a string, 2) an
array of strings, 3) an array of arrays of strings, 4) a hash of arrays
of arrays of strings, 5) a hash of hashes of arrays of arrays of
strings, etc. The problem there is the required homogeneity of the data
-- I though the Perl record structure was supposed to cure that
limitation.

If I understand this right, when I refer to the record (i.e.
non-homogenous data structure -- a widget in my case) I am ALWAYS
referring only to the location of the record, not the contents. There
seems to be no way to store the contents of the record in another
variable -- only its memory address. (I confirmed that an array of
records exhibits this same characteristic).

Is there no way to sort of "de-reference" a record, allowing me to use
it as a variable to collect non-homogeneous data for later storage in
another structure? (I'm grateful for the suggestion of using a method
to get a reference to a hash, but I'm just disillusioned about what I
thought a record was supposed to do... comes from growing up on C and
Pascal, I guess...)
 
T

timdavis919

Thanks for this suggestion Brad, but it won't help in my particular
case.

To extend the terminology in my simple example, for my specific
application, I'm parsing an input file of un-ordered data to build up
my widgets; plus my widgets have not just "colors" and "powers" to
worry about, but 20 or so different characteristics, some of which are
"sub-characteristics" (see below). All widgets have a name, but not all
of them have all of the characteristics. Some have only a name, and
some have multiple values of all the possible characteristics. So
basically, I have to keep reading in "words" from a file until I get a
new widget name, and then start storing multiple values of the
characteristics and sub-characteristics (which are randomly arranged)
until I run across another widget name. Still extending the simple
example I provided, my input data looks something like this:

noise noise noise THINGY noise noise RED noise noise noise HOP noise
noise BLUE noise noise noise SKIP noise noise noise DOODAD noise noise
GREEN noise noise THINGY noise noise BITE noise noise DOODAD noise
JUMP.
From this stream of data, I need to figure out that I have 1) a THINGY
that has colors BLUE and RED as well as (movement) powers SKIP and HOP
with (defensive) powers BITE and 2) a DOODAD that has color GREEN and
power JUMP.

I can do this with by making a bunch of multi-dimension arrays of
strings (for the characteristics, and sub-characteristics), and then
cramming all those into one master array that will go into a hash keyed
by name. That just seemed too much like writing FORTRAN in Perl. The
record structure would have been a much more graceful way to do it --
if Perl records did what I wanted them to do, which does not seem to be
the case. (Sigh.)
 
A

Anno Siegel

Hashes of Records -- who's smarter than me?

I'm hoping that someone who is smarter than me can solve this problem.
It shouldn't be hard -- I suspect I'm doing something obvious and
stupid, but I just can't see it.

I'm trying to create a hash of records, but the contents of all the
records in the hash seem to get overwritten by the contents of the
last record.

I wrote the simplified program below to demonstrate the problem.

In this simplified program I want to create three records (called
widgets) and assign them various characteristics (colors, powers,
etc.) by looping through arrays of those characteristics.

In the example below, I create a widget with name "thingy" color
"red" and power "hop". Then I put it into a hash of records
keyed by name and make sure I can read it out OK. Everything
seems to work.

Leaving out the looping for now, I just assign a new name and some
new characteristics to the record variable and write this second
record to the hash. The values from the second record (a blue
doodad that can skip) seem to overwrite the values in the first
record in the hash. So, although I put in a red thingy that can hop
and a blue doodad that can skip, I end up with two blue doodads --
one of which is still associatd with the hash key for the red thingy.

If anyone can see what the heck I'm doing wrong here, I would be the
happiest guy on the planet -- at least until I realize how embarrassing
my doubtlessly dumb mistake is...

-----------------------------------------------------------------------
CODE BEGINS HERE
-----------------------------------------------------------------------
#!/usr/local/bin/perl

use strict;

my @array_of_strings;
my @AoA_strings;
$AoA_strings[0] = [ @array_of_strings ];

my $widget = {
name => "",
colors => [@array_of_strings],
powers => [@AoA_strings],
};

Your problem is in the lines above. You pre-create the widget data
structure, which is unnecessary (because Perl has autovivification) and
indeed detrimental because you are overwriting the very same data structure
each time you assign new values to $widget.

After you store (a reference to) the widget in %hash_of_widgets, you
go on to fill the same data structure with different data. But that
affects the structure you have already stored in the hash.

Instead, create a new widget structure before you fill in the data and
all will be well. Add

my $widget = {};

here...
my %hash_of_widgets;

my @allnames = ("thingy", "doodad", "whatzit");
my @allcolors = ("red", "blue", "green");
my @allpowers = (
["hop", "skip", "jump"],
["nip", "bite", "decapitate"],
);

# Create a thingy that is red and can hop
$widget->{name} = $allnames[0];
$widget->{colors}[0] = $allcolors[0];
$widget->{powers}[0][0] = $allpowers[0][0];

print "First, we make a $widget->{name} that is $widget->{colors}[0]
and can $widget->{powers}[0][0] \n\n";

#Put the red hopping thingy in the hash
$hash_of_widgets {$widget->{name}} = $widget;

print "Second, when we put it in the hash, we have there:\n";

for my $key (sort keys %hash_of_widgets)
{
print " for the hash key $key: a $hash_of_widgets{$key}->{name} that
is $hash_of_widgets{$key}->{colors}[0] and can
$hash_of_widgets{$key}->{powers}[0][0] \n";
}
print "\n";

# Create a doodad that is blue and can skip

....and here:

my $widget = {};
$widget->{name} = $allnames[1];
$widget->{colors}[0] = $allcolors[1];
$widget->{powers}[0][0] = $allpowers[0][1];

print "Third, we make a $widget->{name} that is $widget->{colors}[0]
and can $widget->{powers}[0][0] \n\n";

$hash_of_widgets {$widget->{name}} = $widget;

print "Fourth, when we put him in the hash we have:\n";

for my $key (sort keys %hash_of_widgets)
{
print " for the hash key $key: a $hash_of_widgets{$key}->{name} that
is $hash_of_widgets{$key}->{colors}[0] and can
$hash_of_widgets{$key}->{powers}[0][0] \n";
}

Your code will now work more like expected.

Anno
 
A

axel

OK, maybe I'm missing something here. What's the point of Perl
implementing a non-homogenous data structure if you can't store the
contents of that data structure in another variable? If one is trying
to build a hierarchy of data structures the Perl record seems like a
dead end. That is, I can build up, for example: 1) a string, 2) an
array of strings, 3) an array of arrays of strings, 4) a hash of arrays
of arrays of strings, 5) a hash of hashes of arrays of arrays of
strings, etc. The problem there is the required homogeneity of the data
-- I though the Perl record structure was supposed to cure that
limitation.

[bits snipped]

Actually this is a very good point at which to consider using objects.
Just as a proof of concept:

File Goat.pm
============
package Goat;

sub spawn {
my $class = shift;
my $self = { };
bless $self, $class;
return $self;
}

sub namegoat {
my $self = shift;
$self->{"name"} = shift;
}

sub setgoatinfo {
my $self = shift;
my ($prop, $value) = (shift, shift);
push @ { $self->{$prop} }, $value;
}

sub getgoatinfo {
my $self = shift;
my $prop = shift;
print $self->{"name"}, " $prop: ", @ { $self->{$prop} }, " \n";
}

1;

File testgoat.pl
================
#!/usr/bin/perl

use warnings;
use strict;

use Data::Dumper;
use Goat;

my %things;
$things{"thingy"} = spawn Goat;

$things{"thingy"}->namegoat ("thingy");
$things{"thingy"}->setgoatinfo (colour => 'red');
$things{"thingy"}->setgoatinfo (colour => 'blue');
$things{"thingy"}->setgoatinfo (colour => 'green');
$things{"thingy"}->setgoatinfo (power => 'hop');
$things{"thingy"}->getgoatinfo ('colour');

print Dumper $things{"thingy"};

__END__

Output
======

thingy colour: redbluegreen
$VAR1 = bless( {
'colour' => [
'red',
'blue',
'green'
],
'power' => [
'hop'
],
'name' => 'thingy'
}, 'Goat' );



Please don't pay too much attention to my rushed together coding at 1am :)

Or why the package is called Goat :)

Axel
 
B

Brad Baxter

Thanks for this suggestion Brad, but it won't help in my particular
case.

To extend the terminology in my simple example, for my specific
application, I'm parsing an input file of un-ordered data to build up
my widgets; plus my widgets have not just "colors" and "powers" to
worry about, but 20 or so different characteristics, some of which are
"sub-characteristics" (see below). All widgets have a name, but not all
of them have all of the characteristics. Some have only a name, and
some have multiple values of all the possible characteristics. So
basically, I have to keep reading in "words" from a file until I get a
new widget name, and then start storing multiple values of the
characteristics and sub-characteristics (which are randomly arranged)
until I run across another widget name. Still extending the simple
example I provided, my input data looks something like this:

noise noise noise THINGY noise noise RED noise noise noise HOP noise
noise BLUE noise noise noise SKIP noise noise noise DOODAD noise noise
GREEN noise noise THINGY noise noise BITE noise noise DOODAD noise
JUMP.

that has colors BLUE and RED as well as (movement) powers SKIP and HOP
with (defensive) powers BITE and 2) a DOODAD that has color GREEN and
power JUMP.

I can do this with by making a bunch of multi-dimension arrays of
strings (for the characteristics, and sub-characteristics), and then
cramming all those into one master array that will go into a hash keyed
by name. That just seemed too much like writing FORTRAN in Perl. The
record structure would have been a much more graceful way to do it --
if Perl records did what I wanted them to do, which does not seem to be
the case. (Sigh.)

Judging from your lack of quoted context, I'll surmise that you haven't
seen Anno's advice, i.e.,

If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.

That aside, I basically think that you are making a bigger problem
out of your problem than there is. The immediate crux of your
question is that you are storing a reference to a structure rather
than an instance of the structure, so to speak. But I think in
general you could simplify things and come out ahead.

Cheers,

Brad
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top