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

Discussion in 'Perl Misc' started by timdavis919@hotmail.com, Dec 6, 2005.

  1. Guest

    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";
    }


    -----------------------------------------------------------------------
    CODE ENDS HERE
    -----------------------------------------------------------------------
     
    , Dec 6, 2005
    #1
    1. Advertising

  2. gantenapalli Guest

    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





    wrote:

    > 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";
    > }
    >
    >
    > -----------------------------------------------------------------------
    > CODE ENDS HERE
    > -----------------------------------------------------------------------
     
    gantenapalli, Dec 6, 2005
    #2
    1. Advertising

  3. Brad Baxter Guest

    wrote:
    > 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;

    --
    Brad
     
    Brad Baxter, Dec 6, 2005
    #3
  4. Guest

    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...)
     
    , Dec 6, 2005
    #4
  5. Guest

    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.)
     
    , Dec 6, 2005
    #5
  6. Anno Siegel Guest

    <> wrote in comp.lang.perl.misc:
    > 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
    --
    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.
     
    Anno Siegel, Dec 7, 2005
    #6
  7. Guest

    <> wrote:
    > 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
     
    , Dec 7, 2005
    #7
  8. Brad Baxter Guest

    wrote:
    > 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.)


    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
     
    Brad Baxter, Dec 7, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ben Holness

    Hashes of Hashes via subs

    Ben Holness, Oct 5, 2003, in forum: Perl
    Replies:
    8
    Views:
    591
    Ben Holness
    Oct 8, 2003
  2. Luc The Perverse

    Smarter than BigDecimal Class

    Luc The Perverse, Jul 17, 2006, in forum: Java
    Replies:
    6
    Views:
    1,806
    Patricia Shanahan
    Jul 17, 2006
  3. Steven Arnold

    using hashes as keys in hashes

    Steven Arnold, Nov 23, 2005, in forum: Ruby
    Replies:
    3
    Views:
    185
    Mauricio Fernández
    Nov 23, 2005
  4. kazaam
    Replies:
    12
    Views:
    295
    Matthias Wächter
    Sep 13, 2007
  5. Tim O'Donovan

    Hash of hashes, of hashes, of arrays of hashes

    Tim O'Donovan, Oct 27, 2005, in forum: Perl Misc
    Replies:
    5
    Views:
    237
Loading...

Share This Page