hash whose values are arrays of hashes

Discussion in 'Perl Misc' started by davidmichaelkarr@gmail.com, May 31, 2006.

  1. Guest

    I've paged through the docs on arrays and hashes, but I can't find a
    clear answer for my situation.

    I'm trying to build a hash keyed by a string, where the values are
    arrays of hashes. I'll need to add new hashes to the array for
    particular keys in the main hash. Later, I'll need to step through the
    keys of the main hash and operate on the data in each hash in the
    array.

    I've tried several variations of this, and it doesn't quite work yet.

    Each time I have a new hash to add to the array associated with a key,
    I'll need to append the new hash to the end of the array.

    I think part of the problem here is that it's not obvious how to add a
    hash to the end of an array, without it "opening up" the has into an
    array of the keys and values. I think it might require using a
    reference to the hash instead, but I'm not sure.

    For instance, I figure that the following is a "manual" construction of
    a hash holding arrays of hashes, but maybe I'm wrong:

    my %testhash = ("abc" => (("xxx" => "yyy"), ("aaa" => "bbb")),
    "def" => (("jjj" => "kkk"), ("ppp" =>
    "qqq")));

    If I try to reference the "abc" key, like this:

    print $testhash{"abc"};

    it prints "xxx". I'm not certain what that indicates.
     
    , May 31, 2006
    #1
    1. Advertising

  2. wrote:
    > I've paged through the docs on arrays and hashes, but I can't find a
    > clear answer for my situation.
    >
    > I'm trying to build a hash keyed by a string, where the values are
    > arrays of hashes. I'll need to add new hashes to the array for
    > particular keys in the main hash. Later, I'll need to step through the
    > keys of the main hash and operate on the data in each hash in the
    > array.
    >
    > I've tried several variations of this, and it doesn't quite work yet.
    >
    > Each time I have a new hash to add to the array associated with a key,
    > I'll need to append the new hash to the end of the array.
    >
    > I think part of the problem here is that it's not obvious how to add a
    > hash to the end of an array, without it "opening up" the has into an
    > array of the keys and values. I think it might require using a
    > reference to the hash instead, but I'm not sure.
    >
    > For instance, I figure that the following is a "manual" construction of
    > a hash holding arrays of hashes, but maybe I'm wrong:
    >
    > my %testhash = ("abc" => (("xxx" => "yyy"), ("aaa" => "bbb")),
    > "def" => (("jjj" => "kkk"), ("ppp" =>
    > "qqq")));


    By using parentheses you are creating one list similar to:

    my %testhash = qw( abc xxx yyy aaa bbb def jjj kkk ppp qqq );

    You need to use [] to create anonymous arrays and {} to create anonymous hashes:

    my %testhash = ( abc => [ { xxx => 'yyy' }, { aaa => 'bbb' } ],
    def => [ { jjj => 'kkk' }, { ppp => 'qqq' } ] );



    John
    --
    use Perl;
    program
    fulfillment
     
    John W. Krahn, Jun 1, 2006
    #2
    1. Advertising

  3. Guest

    John W. Krahn wrote:
    > wrote:
    > > I've paged through the docs on arrays and hashes, but I can't find a
    > > clear answer for my situation.
    > >
    > > I'm trying to build a hash keyed by a string, where the values are
    > > arrays of hashes. I'll need to add new hashes to the array for
    > > particular keys in the main hash. Later, I'll need to step through the
    > > keys of the main hash and operate on the data in each hash in the
    > > array.
    > >
    > > I've tried several variations of this, and it doesn't quite work yet.
    > >
    > > Each time I have a new hash to add to the array associated with a key,
    > > I'll need to append the new hash to the end of the array.
    > >
    > > I think part of the problem here is that it's not obvious how to add a
    > > hash to the end of an array, without it "opening up" the has into an
    > > array of the keys and values. I think it might require using a
    > > reference to the hash instead, but I'm not sure.
    > >
    > > For instance, I figure that the following is a "manual" construction of
    > > a hash holding arrays of hashes, but maybe I'm wrong:
    > >
    > > my %testhash = ("abc" => (("xxx" => "yyy"), ("aaa" => "bbb")),
    > > "def" => (("jjj" => "kkk"), ("ppp" =>
    > > "qqq")));

    >
    > By using parentheses you are creating one list similar to:
    >
    > my %testhash = qw( abc xxx yyy aaa bbb def jjj kkk ppp qqq );
    >
    > You need to use [] to create anonymous arrays and {} to create anonymous hashes:
    >
    > my %testhash = ( abc => [ { xxx => 'yyy' }, { aaa => 'bbb' } ],
    > def => [ { jjj => 'kkk' }, { ppp => 'qqq' } ] );


    Ok, then consider this:

    my %testhash = {abc => [ {xxx => 'yyy', jjj => 'mmm'}, {aaa => 'bbb',
    ccc => 'ddd'} ],
    def => [ {jjj => 'kkk', ppp => 'qqq'} ]
    };

    my @stuff = $testhash{'abc'};
    my %hash = $stuff[0];
    print "xxx[". $hash{'xxx'} . "]\n";
    print "jjj[" . $hash{'jjj'} . "]\n";

    Both of these print statements print empty strings for their values.

    I thought perhaps two two references should be "$hash{xxx]" and
    "$hash{jjj}" instead, but that had no effect. It still appeared to be
    empty.
     
    , Jun 1, 2006
    #3
  4. wrote:
    > John W. Krahn wrote:
    >> wrote:
    >>>
    >>>my %testhash = ("abc" => (("xxx" => "yyy"), ("aaa" => "bbb")),
    >>> "def" => (("jjj" => "kkk"), ("ppp" =>
    >>>"qqq")));

    >>By using parentheses you are creating one list similar to:
    >>
    >>my %testhash = qw( abc xxx yyy aaa bbb def jjj kkk ppp qqq );
    >>
    >>You need to use [] to create anonymous arrays and {} to create anonymous hashes:
    >>
    >>my %testhash = ( abc => [ { xxx => 'yyy' }, { aaa => 'bbb' } ],

    ^^^

    >> def => [ { jjj => 'kkk' }, { ppp => 'qqq' } ] );

    >
    > Ok, then consider this:
    >
    > my %testhash = {abc => [ {xxx => 'yyy', jjj => 'mmm'}, {aaa => 'bbb',

    ^^^

    You are assigning a single anonymous hash to %testhash. Do you have strict
    and warnings enabled?

    > ccc => 'ddd'} ],
    > def => [ {jjj => 'kkk', ppp => 'qqq'} ]
    > };
    >
    > my @stuff = $testhash{'abc'};


    $testhash{'abc'} contains a single scalar value. If that value is a reference
    to an array you need to dereference it.

    my @stuff = @{$testhash{'abc'}};



    perldoc perlreftut
    perldoc perlref
    perldoc perldsc
    perldoc perllol



    John
    --
    use Perl;
    program
    fulfillment
     
    John W. Krahn, Jun 1, 2006
    #4
  5. John Bokma Guest

    wrote:

    > I've paged through the docs on arrays and hashes, but I can't find a
    > clear answer for my situation.
    >
    > I'm trying to build a hash keyed by a string, where the values are
    > arrays of hashes.



    my %example = (

    abc => [

    {
    xxx => 'yyy',
    }
    {

    aaa => 'bbb',
    }

    ]
    );


    > I'll need to add new hashes to the array for
    > particular keys in the main hash.



    push @{ $example{ 'abc' } }, { jjj => 'kkk' };


    > Later, I'll need to step through the
    > keys of the main hash and operate on the data in each hash in the
    > array.


    for my $key ( keys %example ) {

    for my $hash ( @{ $example{ $key } } ) {

    # $hash is now a reference to an element (hash) in
    # the array. The reference to this array is a value
    # stored in the example hash with key $key.
    }
    }

    > Each time I have a new hash to add to the array associated with a key,
    > I'll need to append the new hash to the end of the array.


    perldoc -f push

    if $example{ 'abc' } is a reference to an array, then you can derefence
    it with @ and use push to add a reference to a hash, i.e.

    push @{ $example{ 'abc' } }, { jjj => 'kkk' };


    print $example{ 'abc' }[ -1 ]{ 'jjj' };

    should give kkk

    -1 = last item in array.

    > I think part of the problem here is that it's not obvious how to add a
    > hash to the end of an array, without it "opening up" the has into an
    > array of the keys and values.


    So you add a reference to a hash to an array.

    > I think it might require using a
    > reference to the hash instead, but I'm not sure.


    If you want to eliminate duplicates, not. I assumed you don't want to do
    this, and hence used references in the example above, because that comes
    closer to an array of hashes.

    A tip:

    use Data::Dumper;

    :
    :
    :

    print Dumper \%example;

    this shows how things are stored, wich might come in very handy when
    working with complicated datastructures.

    As using pen and paper to draw first the data structure :-D.

    --
    John Bokma Freelance software developer
    &
    Experienced Perl programmer: http://castleamber.com/
     
    John Bokma, Jun 1, 2006
    #5
  6. Dr.Ruud Guest

    John Bokma schreef:

    > my %example = (
    >
    > abc => [
    >
    > {
    > xxx => 'yyy',
    > }


    Missing: comma.

    > {
    >
    > aaa => 'bbb',
    > }
    >
    > ]
    > );



    perl -MO=Deparse -we '
    <the original code>
    '
    syntax error at -e line 9, near "{"

    --
    Affijn, Ruud

    "Gewoon is een tijger."
     
    Dr.Ruud, Jun 1, 2006
    #6
  7. david.karr Guest

    John Bokma wrote:
    > wrote:
    >
    > > I've paged through the docs on arrays and hashes, but I can't find a
    > > clear answer for my situation.
    > >
    > > I'm trying to build a hash keyed by a string, where the values are
    > > arrays of hashes.

    >
    >
    > my %example = (
    >
    > abc => [
    > [deleted]
    > ]
    > );
    >
    > > I'll need to add new hashes to the array for
    > > particular keys in the main hash.

    >
    > push @{ $example{ 'abc' } }, { jjj => 'kkk' };


    When I do something like this:

    my %testhash = {abc => [ {xxx => 'yyy', jjj => 'mmm'},
    {aaa => 'bbb', ccc => 'ddd'}
    ],
    def => [ {jjj => 'kkk', ppp => 'qqq'} ] };

    my @stuff = @{$testhash{'abc'}};

    It complains:

    "Can't use an undefined value as an ARRAY reference at ..."

    > > I think part of the problem here is that it's not obvious how to add a
    > > hash to the end of an array, without it "opening up" the has into an
    > > array of the keys and values.

    >
    > So you add a reference to a hash to an array.
    >
    > > I think it might require using a
    > > reference to the hash instead, but I'm not sure.

    >
    > If you want to eliminate duplicates, not. I assumed you don't want to do
    > this, and hence used references in the example above, because that comes
    > closer to an array of hashes.


    I'm not exactly certain what you're recommending here.

    For background, my hash of arrays of hashes will be built up
    incrementally, processing a set of log files one by one, using a
    substring from each line as the key to the main hash, and each entry of
    the array keyed by that string represents lines where that substring
    was present. The hash in each array entry represents the fields found
    in each line.

    So, on each line of each file, I have a "my" hash that stores the
    fields of the line, including the "key" field. I then get the array of
    lines using the same key from the main hash. This array could be empty
    if this is the first line with this key value. I then add the new
    "line" hash to the array for the main key.

    Once I've built up this data structure (and some similar ones), I'll
    iterate through the data structures and generate some statistics from
    the values found.

    Based on this, I don't believe I need to worry about whether I'm
    removing duplicates or not, as the "line" hash is created for each line
    of each log file.

    > A tip:
    >
    > use Data::Dumper;


    I'll definitely look at this, once my code compiles :) .
     
    david.karr, Jun 1, 2006
    #7
  8. Paul Lalli Guest

    david.karr wrote:
    > When I do something like this:
    >
    > my %testhash = {abc => [ {xxx => 'yyy', jjj => 'mmm'},
    > {aaa => 'bbb', ccc => 'ddd'}
    > ],
    > def => [ {jjj => 'kkk', ppp => 'qqq'} ] };
    >
    > my @stuff = @{$testhash{'abc'}};
    >
    > It complains:
    >
    > "Can't use an undefined value as an ARRAY reference at ..."


    If you'd enable warnings in your code, Perl would tell you about the
    real problem here, rather than just the first truly impossible thing
    that happened.

    You assigned your hash to have one key with no value. That one key is
    a reference to a hash whose keys are 'abc' and 'def'.

    Change the outer { } to ( ). And always, yes *always* include the
    lines
    use strict;
    use warnings;
    right under the shebang.

    Paul Lalli
     
    Paul Lalli, Jun 1, 2006
    #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. Replies:
    4
    Views:
    104
    Jeremy Evans
    Aug 21, 2007
  2. Tore Aursand
    Replies:
    3
    Views:
    578
    Anno Siegel
    Sep 16, 2003
  3. Scott  Gilpin
    Replies:
    2
    Views:
    237
  4. Perl Learner

    Hashes of hashes or just one hash ?

    Perl Learner, Jun 8, 2005, in forum: Perl Misc
    Replies:
    11
    Views:
    232
  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:
    235
Loading...

Share This Page