Odd number of elements in hash assignment

Odd number of elements in hash assignment

Post by De » Tue, 11 Mar 2003 07:39:47



Still struggling with multilevel hashes.  Below is my code snippet, obligatory
use statments are in effect.  I don't understand the error.  Line 52 refers
to the line %hrLists assignment -

Where did I go wrong?

Thanks,
deb

while (<DATA>) {
    chomp;
    ($listname, $field) = split(/:/, $_);
    print "\nListname is $listname,\nField is: $field\n";
    %hrLists = split(/\s+/, $field);
    $Lists{$listname} = \%hrLists;

Quote:}

__DATA__
list-1: -x abc -r tenb
list-2: -x def -r ghi -h tenr
list-3: -x fel -h asci
list-4: -x foo -h nonasci -r bfab

I'm getting this output:

Listname is list-1,
Field is:  -x abc -r tenb
Odd number of elements in hash assignment at testhash2.pl line 52, <DATA> line 1.

Listname is list-2,
Field is:  -x def -r ghi -h tenr
Odd number of elements in hash assignment at testhash2.pl line 52, <DATA> line 2.

Listname is list-3,
Field is:  -x fel -h asci
Odd number of elements in hash assignment at testhash2.pl line 52, <DATA> line 3.

Listname is list-4,
Field is:  -x foo -h nonasci -r bfab
Odd number of elements in hash assignment at testhash2.pl line 52, <DATA> line 4.

 
 
 

Odd number of elements in hash assignment

Post by Steve Grazzi » Tue, 11 Mar 2003 08:03:30



> Still struggling with multilevel hashes.

<snip>

Quote:> while (<DATA>) {
>     chomp;
>     ($listname, $field) = split(/:/, $_);
>     print "\nListname is $listname,\nField is: $field\n";
>     %hrLists = split(/\s+/, $field);
>     $Lists{$listname} = \%hrLists;
> }

> __DATA__
> list-1: -x abc -r tenb
> list-2: -x def -r ghi -h tenr
> list-3: -x fel -h asci
> list-4: -x foo -h nonasci -r bfab

> I'm getting this output:

> Listname is list-1,
> Field is:  -x abc -r tenb
> Odd number of elements in hash assignment ...

You're getting an empty leading field;

  $ perldoc -f split
  <relevant bits>

      Splits a string into a list of strings and returns
      that list.  By default, empty leading fields are
      preserved, and empty trailing ones are deleted.

      If EXPR is omitted, splits the "$_" string.  If
      PATTERN is also omitted, splits on whitespace
      (after skipping any leading whitespace).  Anything
      matching PATTERN is taken to be a delimiter
      separating the fields.  (Note that the delimiter
      may be longer than one character.)

      As a special case, specifying a PATTERN of space
      ("' '") will split on white space just as "split"
      with no arguments does.  Thus, "split(' ')" can be
      used to emulate awk's default behavior, whereas
      "split(/ /)" will give you as many null initial
      fields as there are leading spaces.  A "split" on
      "/\s+/" is like a "split(' ')" except that any
      leading whitespace produces a null first field.  A
      "split" with no arguments really does a "split('
      ', $_)" internally.

So try something like this:

    use Data::Dumper;

    while (<DATA>) {
        chomp;
        my ($listname, $field) = split /:/;
        $Lists{$listname} = split ' ', $field;

        #
        # would have helped you spot it...
        #
        print "listname:'$listname'\n",
              "field:   '$field'\n",
               Dumper $Lists{$listname};
    }

HTH
--
Steve

 
 
 

Odd number of elements in hash assignment

Post by De » Tue, 11 Mar 2003 09:34:16


Thanks for the quick reply...

Okay, I could use Data::Dumper, but what do you mean by empty
leading field?  Am I dense? (probably!)

I don't really want to use D::D module, so what would I do to
alleviate this?  Ensure no leading white space?  I'll have to
give that a try (but my kids are not lettying me tayp; fdsa
right nows.)

Tnx!



> > Still struggling with multilevel hashes.
> <snip>
>=20
> > while (<DATA>) {
> >     chomp;
> >     ($listname, $field) =3D split(/:/, $_);
> >     print "\nListname is $listname,\nField is: $field\n";
> >     %hrLists =3D split(/\s+/, $field);
> >     $Lists{$listname} =3D \%hrLists;
> > }
> >=20
> > __DATA__
> > list-1: -x abc -r tenb
> > list-2: -x def -r ghi -h tenr
> > list-3: -x fel -h asci
> > list-4: -x foo -h nonasci -r bfab
> >=20
> > I'm getting this output:
> >=20
> > Listname is list-1,
> > Field is:  -x abc -r tenb
> > Odd number of elements in hash assignment ...
>=20
> You're getting an empty leading field;
>=20
>   $ perldoc -f split=20
>   <relevant bits>
>=20
>       Splits a string into a list of strings and returns
>       that list.  By default, empty leading fields are
>       preserved, and empty trailing ones are deleted.
>=20
>       If EXPR is omitted, splits the "$_" string.  If
>       PATTERN is also omitted, splits on whitespace
>       (after skipping any leading whitespace).  Anything
>       matching PATTERN is taken to be a delimiter
>       separating the fields.  (Note that the delimiter
>       may be longer than one character.)
>=20
>       As a special case, specifying a PATTERN of space
>       ("' '") will split on white space just as "split"
>       with no arguments does.  Thus, "split(' ')" can be
>       used to emulate awk's default behavior, whereas
>       "split(/ /)" will give you as many null initial
>       fields as there are leading spaces.  A "split" on
>       "/\s+/" is like a "split(' ')" except that any
>       leading whitespace produces a null first field.  A
>       "split" with no arguments really does a "split('
>       ', $_)" internally.
>=20
>=20
> So try something like this:
>=20
>     use Data::Dumper;
>=20
>     while (<DATA>) {
>         chomp;
>         my ($listname, $field) =3D split /:/;
>         $Lists{$listname} =3D split ' ', $field;
>        =20
>         #
>         # would have helped you spot it...
>         #
>         print "listname:'$listname'\n",
>               "field:   '$field'\n",=20
>                Dumper $Lists{$listname};
>     }
>=20
> HTH
> --=20
> Steve
>=20
> --=20



--=20
=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D=
-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=
=3D-=3D-=3D-
          There are 010 types of people in the world:
       those who understand binary, and those who don't.
=F4=BF=F4   111,111,111 x 111,111,111 =3D 12,345,678,987,654,321 (decimal)
 ~=20
 
 
 

Odd number of elements in hash assignment

Post by De » Tue, 11 Mar 2003 10:01:53


All,

Replying to my own post - yup, that did it.  I removed the leading
space(s), then did the hash ref assignment, and all was well.

Whew!

Thanks for the tip - and the pointer that I should have checked the
docs...  sometimes the problem is that I'm just not sure *which* doc
would have the info I'm looking for!

G'Day,

deb

Deb sez,

Quote:> Thanks for the quick reply...

> Okay, I could use Data::Dumper, but what do you mean by empty
> leading field?  Am I dense? (probably!)

> I don't really want to use D::D module, so what would I do to
> alleviate this?  Ensure no leading white space?  I'll have to
> give that a try (but my kids are not lettying me tayp; fdsa
> right nows.)

 
 
 

Odd number of elements in hash assignment

Post by R. Joseph Newt » Tue, 11 Mar 2003 10:22:30



> Thanks for the quick reply...

> Okay, I could use Data::Dumper, but what do you mean by empty
> leading field?  Am I dense? (probably!)

> I don't really want to use D::D module, so what would I do to
> alleviate this?  Ensure no leading white space?  I'll have to
> give that a try (but my kids are not lettying me tayp; fdsa
> right nows.)

> Tnx!

Hi Deb,

The leading space is that between the colon seperator and the first element.  You can eliminate it with no extra coding by changing your first split statment:
($listname, $field) = split(/:\s+/, $_);

Joseph

 
 
 

Odd number of elements in hash assignment

Post by De » Wed, 12 Mar 2003 01:54:53


You know, I'm just not "getting it" I guess.  When I read through
simple of examples in perldsc and perlfunc, it seems straightforward
enough, but when I try to put into practice everything, it doesn't go
as I might expect.

Recall this code I posted a day or two ago:

-------- 8-< -- snip --------

while (<DATA>) {
    chomp;
    ($listname, $field) = split(/:\s+/, $_);
    print "\nListname is $listname,\nField is: $field\n";
    %hrLists = split(/\s+/, $field);
    $Lists{$listname} = \%hrLists;

Quote:}

__DATA__
list-1: -x abc -r tenb
list-2: -x def -r ghi -h tenr
list-3: -x fel -h asci
list-4: -x foo -h nonasci -r bfab

-------- 8-< -- snip --------

Note the print in the while loop - essentially, when the hash is built,  my
goal is to be able to use $listname as a key to call up the value of a key in
the 2nd level hash.

I understand this:

foreach $listname (sort keys %Lists) {
    print "$listname\n";

Quote:}

But, I don't quite get how to get to the key values below that.  I know I'm so
close, but just not quite there...

Could some kind soul give me a blow by blow "what's happening here" going from

        $Lists{$listname} = \%hrLists;

to printing out the key, values by $listname?

Thanks,
deb

 
 
 

Odd number of elements in hash assignment

Post by Timothy Johns » Wed, 12 Mar 2003 02:18:30


------>8-----------------------------
"I understand this:

foreach $listname (sort keys %Lists) {
    print "$listname\n";

Quote:}

------>8-----------------------------

To get the values instead of the keys, you will have to do something like
this:

foreach $listkey (sort keys %Lists){
    print "$List{$listkey}\n";

Quote:}

Or, if you want the values sorted, you want something more like this:

foreach $listkey (sort {$Lists{$a} cmp $Lists{$b}} keys %Lists){
    print "$List{$listkey}\n";

Quote:}

This part might look a little confusing at first:

    sort { $Lists{$a} cmp $Lists{$b} } keys %Lists

but it's a useful trick, especially when your "key" is a reference or other
"unreadable" variable.

 
 
 

Odd number of elements in hash assignment

Post by De » Wed, 12 Mar 2003 02:48:27


I'm not sure what you're saying.  Since this is an anonymous hash assignment,
how do I pull out the $listkey?  Do I need to pre-assign it?  For example,
I tried this, added to the previous program,

foreach $listname (sort keys %Lists) {
    print "$listname:\n";
    foreach $key (sort keys %Lists) {
        print "\t$Lists{$key}\n";
    }

Quote:}

And the out put is,

list-1:
        HASH(0x55750)
        HASH(0x55750)
        HASH(0x55750)
        HASH(0x55750)
list-2:
        HASH(0x55750)
        HASH(0x55750)
        HASH(0x55750)
        HASH(0x55750)
list-3:
        HASH(0x55750)
        HASH(0x55750)
        HASH(0x55750)
        HASH(0x55750)
list-4:
        HASH(0x55750)
        HASH(0x55750)
        HASH(0x55750)
        HASH(0x55750)

So, Iguess I just pulled out the reference to the location?  

My initial request remains,

: But, I don't quite get how to get to the key values below that.  I know I'm so
: close, but just not quite there...
:
: Could some kind soul give me a blow by blow "what's happening here" going from

    $Lists{$listname} = \%hrLists;

: to printing out the key, values by $listname?


Quote:> To get the values instead of the keys, you will have to do something like
> this:

> foreach $listkey (sort keys %Lists){
>     print "$List{$listkey}\n";
> }

> Or, if you want the values sorted, you want something more like this:

> foreach $listkey (sort {$Lists{$a} cmp $Lists{$b}} keys %Lists){
>     print "$List{$listkey}\n";
> }

> This part might look a little confusing at first:

>     sort { $Lists{$a} cmp $Lists{$b} } keys %Lists

> but it's a useful trick, especially when your "key" is a reference or other
> "unreadable" variable.

 
 
 

Odd number of elements in hash assignment

Post by Steve Grazzi » Wed, 12 Mar 2003 03:32:59



> I understand this:

> foreach $listname (sort keys %Lists) {
>     print "$listname\n";
> }

> But, I don't quite get how to get to the key values
> below that.  I know I'm so close, but just not quite
> there...

> Could some kind soul give me a blow by blow "what's
> happening here" going from

>    $Lists{$listname} = \%hrLists;

> to printing out the key, values by $listname?

Don't mean to thump the FM, but have you seen the
"Access and Printing of a HASH OF HASHES" section
in perldsc?  Your %Lists is a perfect %HoH.

But anyway, as you've probably seen, the ordinary
"print a hash" loop...

    for my $key (sort keys %Lists) {
      print "$key => $Lists{$key}\n";
    }

Produces something like this.

    list-1 => HASH(0x80fb32c)

Where "HASH(0x80fb32c)" represents the hash reference.
you created way... back.. here:

    $Lists{$listname} = \%hrLists;
    #                   ^
    # backslash creates a reference
    #

So what you've got is a nested data structure; a
hash (%List) whose values are references to more
hashes.

To print it out, you just need two loops, an outer
loop for %Lists, and an inner loop to iterate over
the nested hashes.

  for my $list (sort keys %Lists) {
    print "$list: \n";

    my $ref = $Lists{$list};

    #
    # use "%{$ref}" to dereference
    #
    for my $key (sort keys %{$ref}) {
      print "  $key : $ref->{$key}\n";
    }
  }

And besides perldsc, you might find these handy if
you're learning/working-with references:

  $ perldoc perlreftut
  $ perldoc perlref

--
Steve

 
 
 

Odd number of elements in hash assignment

Post by De » Wed, 12 Mar 2003 12:04:54


Thanks, Steve, for your feedback.  As I said in private email to Steve
earlier today, I don't mind someone thumping the FM to me - problem is, I've
been reading all the FM I could find, including all those mentioned here.
Got the printouts right in front of me.

But I've been confused by different approaches presented, vs. what I need to
do... which is why I think I got close, but not quite there.

I was still getting hung up in the syntax especially as it relates to
anonymous data structures, vs named ones.  Not really apples and oranges, but
one really needs to understand syntactically how to pull it out of annonymous
hashes, if you *don't* want to use a literal to obtain a key,

        $xKey = $hash{'-x'}

to then iterate over the hash to get the value. Yuck.

Still chewing on the bones...

deb


> Don't mean to thump the FM, but have you seen the
> "Access and Printing of a HASH OF HASHES" section
> in perldsc?  Your %Lists is a perfect %HoH.

> But anyway, as you've probably seen, the ordinary
> "print a hash" loop...

>     for my $key (sort keys %Lists) {
>       print "$key => $Lists{$key}\n";
>     }

> Produces something like this.

>     list-1 => HASH(0x80fb32c)

> Where "HASH(0x80fb32c)" represents the hash reference.
> you created way... back.. here:

>     $Lists{$listname} = \%hrLists;
>     #                   ^
>     # backslash creates a reference
>     #

> So what you've got is a nested data structure; a
> hash (%List) whose values are references to more
> hashes.

> To print it out, you just need two loops, an outer
> loop for %Lists, and an inner loop to iterate over
> the nested hashes.

>   for my $list (sort keys %Lists) {
>     print "$list: \n";

>     my $ref = $Lists{$list};

>     #
>     # use "%{$ref}" to dereference
>     #
>     for my $key (sort keys %{$ref}) {
>       print "  $key : $ref->{$key}\n";
>     }
>   }

> And besides perldsc, you might find these handy if
> you're learning/working-with references:

>   $ perldoc perlreftut
>   $ perldoc perlref

> --
> Steve

> --



--
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
          There are 010 types of people in the world:
       those who understand binary, and those who don't.
???   111,111,111 x 111,111,111 = 12,345,678,987,654,321 (decimal)
 ~
 
 
 

Odd number of elements in hash assignment

Post by R. Joseph Newt » Wed, 12 Mar 2003 13:10:31



> I'm not sure what you're saying.  Since this is an anonymous hash assignment,
> how do I pull out the $listkey?  Do I need to pre-assign it?  For example,
> I tried this, added to the previous program,

> foreach $listname (sort keys %Lists) {
>     print "$listname:\n";
>     foreach my $key (sort keys %{$Lists{$listname}}) {
>         print "\t$key:  ${$Lists{$listname}}{$key}\n";
>     }
> }

Try something like the changes above.  The clue that something was wrong with the way you had it set up was that you foreach'ed on the same array in the inner loop as the outer.  In a nested loop structure, the inner loop should build on the work done by the outer.  Here, the outer loop directs you to the hash representing a given command line.  The reference to that hash is the element $Lists{$listname}.  This is equivalent to the bare name of the hash--without the %.  So to get the keys hash, you should hashify the reference by prepending the %:
%{$Lists{$listname})}   # NOTE braces
Likewise, you can get the second level, element by prepending the scalar symbol $ and citing a key.
${$Lists{$listname}}{$key}

Thanks.  This exercise taught me a few things about dereferencing.  Particularly to enclose a reference such as $Lists{$listname} in braces, rather than parens, to get at the payload.
The line:
        print "\t$key:  ${$Lists{$listname}}{$key}\n";
could also be written:
        print "\t$key:  $Lists{$listname}->{$key}\n";
I prefer the first myself, because I think it communicates more directly the logic of the dereference.  That is totally a matter of taste, though.  TIMTOWTDI.

Joseph

Here's what I drew out of this note the use strict and adaptations to satisfy compilation rules:

#!/usr/bin/perl -w

use strict;

my %Lists;

while (<DATA>) {
    chomp;
    my ($listname, $field) = split(/:\s+/, $_);
    print "\nListname is $listname,\nField is: $field\n";
    my %hrLists = split(/\s+/, $field);
    $Lists{$listname} = \%hrLists;

Quote:}

foreach my $listname (sort keys %Lists) {
    print "$listname:\n";
    foreach my $key (sort keys %{$Lists{$listname}}) {
        print "\t$key:  ${$Lists{$listname}}{$key}\n";
    }

Quote:}

__DATA__
list-1: -x abc -r tenb
list-2: -x def -r ghi -h tenr
list-3: -x fel -h asci
list-4: -x foo -h nonasci -r bfab

OUTPUT:
E:\d_drive\perlStuff\guests>deb2dhash.pl

Listname is list-1,
Field is: -x abc -r tenb

Listname is list-2,
Field is: -x def -r ghi -h tenr

Listname is list-3,
Field is: -x fel -h asci

Listname is list-4,
Field is: -x foo -h nonasci -r bfab
list-1:
        -r:  tenb
        -x:  abc
list-2:
        -h:  tenr
        -r:  ghi
        -x:  def
list-3:
        -h:  asci
        -x:  fel
list-4:
        -h:  nonasci
        -r:  bfab
        -x:  foo

E:\d_drive\perlStuff\guests>

 
 
 

Odd number of elements in hash assignment

Post by De » Thu, 13 Mar 2003 03:02:09


The light is beginning to shine a little brighter...

Joseph's cogent explanation of dereferencing is helpful.  Thanks.

Yesterday I went out and bought the 3rd edition to the Perl reference book by
ORA (mine was a very old 1st edition).  The 3rd edition has a whole lot more
on references than the 1st edition even dreamed about including.

(set me back $50, but in the long run should be well worth it)

The only thing left now is to be able to add new key, values to the %Lists
hash, as my program comes across them.

deb