Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Access hash of hashes element problem.

Reply
Thread Tools

Access hash of hashes element problem.

 
 
Justin C
Guest
Posts: n/a
 
      05-01-2007

I can't seem to access the values in a hash of hashes, but if I iterate
over it I'm able to print all the values. The error I get if I try to
access one value is :
Use of uninitialized value in print at ./test line 20, <PRICES> line 62.

I've done the best I can in reducing this to the smallest possible code
that works, it's still quite long, sorry about that.

======= START CODE =======
#!/usr/bin/perl

use warnings ;
use strict ;

my %priceHash ;
my $zone = 5 ;
my $weight = 5 ;

lookupCost() ;

#for $weight ( keys %priceHash ) {
# print "$weight : " ;
# for $zone ( keys %{$priceHash{$weight}} ) {
# print "\t", $zone, "=", $priceHash{$weight}{$zone}, "\n" ;
# }
# print "\n" ;
#}

print "Price = ", $priceHash{$weight}{$zone}, "\n" ;

sub lookupCost {
open PRICES, "<", "/var/www/inhouse/pforce/pforcePrices.csv"
or die "Cannot opne prices csv file: $!" ;

my @lines = <PRICES> ;
my $header = shift @lines ;
chomp $header ;
$header =~ s/\cM//g ; # MS CR/LF
$header =~ s/zone//ig ;
$header =~ s/\s+//g ;

my @zones = split /,/ , $header ;
shift @zones ; #first one is empty
foreach ( @lines ) {
chomp ;
s/\cM//g ;
my @prices = split /,/ ;
my $kg = shift @prices ;

foreach ( @zones ) {
$priceHash{$kg}{$_} = shift @prices ;
}
}
}
======= CODE END =======

If I comment the "print" line and uncomment the itteration over the
hashes it prints, for each weight, the different zones and the prices
for those zones. It appears to me that all of the information is in the
hash but I'm not accessing the individual values correctly.

The .csv, if you want to try this out, can be found at:
http://81.6.247.208/pforcePrices.csv I didn't paste it here because of
the size (it's not too big, but it's not appropriate for a usenet post).

I thank you for any help you can give with this.

Justin.

--
Justin C, by the sea.
 
Reply With Quote
 
 
 
 
J. Gleixner
Guest
Posts: n/a
 
      05-01-2007
alexamaschoolJustin C wrote:
> I can't seem to access the values in a hash of hashes, but if I iterate
> over it I'm able to print all the values. The error I get if I try to
> access one value is :
> Use of uninitialized value in print at ./test line 20, <PRICES> line 62.
>
> I've done the best I can in reducing this to the smallest possible code
> that works, it's still quite long, sorry about that.


It could be smaller. Use __DATA__, for a few lines, of your CSV
file in your script so that others can run it without having to
download your CSV file.

You could use Data:umper to verify what's actually in %priceHash.

use Data:umper;
print Dumper( \%priceHash );
 
Reply With Quote
 
 
 
 
Mumia W.
Guest
Posts: n/a
 
      05-01-2007
On 05/01/2007 10:39 AM, Justin C wrote:
> I can't seem to access the values in a hash of hashes, but if I iterate
> over it I'm able to print all the values. The error I get if I try to
> access one value is :
> Use of uninitialized value in print at ./test line 20, <PRICES> line 62.
> [...]


Your program is so close to working, but you have one problem--you
forgot that hash keys are strings and only strings. Where string
comparisons are concerned, '5' != '5.0'. Change $weight (at the top of
the program) to "5.0" and rerun your program.

However, it's better to create the hash keys as simpler numbers, e.g.
insert 5 rather than 5.0:

$priceHash{$kg+0}{$_} = shift @prices;

This causes a warning about "per" which has some function in your data
that I don't know about.

I also have two minor nickpicks: "open" is misspelled in the die()
statement, and the PRICES file is never explicitly closed by program.
You also do a little more work than is necessary to read in the data.

This is a shorter version of your program:

use strict;
use warnings;
use File::Slurp;

my %priceHash;
my $weight = 5;
my $zone = 5;

my @lines = read_file('pforcePrices.csv');
s/\cM\cJ$// for @lines;

my $header = shift @lines;
$header =~ s/(zone|\s+|^,)//ig;
my @zones = split /,/,$header;

foreach my $line (@lines) {
next unless $line =~ /^\d/;
my @prices = split /,/,$line;
my $kg = shift @prices;
foreach my $zn (@zones) {
$priceHash{$kg+0}{$zn} = shift @prices;
}
}

print "Price: $priceHash{$weight}{$zone}\n";

 
Reply With Quote
 
Jens Thoms Toerring
Guest
Posts: n/a
 
      05-01-2007
Justin C <(E-Mail Removed)> wrote:
> I can't seem to access the values in a hash of hashes, but if I iterate
> over it I'm able to print all the values. The error I get if I try to
> access one value is :
> Use of uninitialized value in print at ./test line 20, <PRICES> line 62.


> I've done the best I can in reducing this to the smallest possible code
> that works, it's still quite long, sorry about that.


> ======= START CODE =======
> #!/usr/bin/perl


> use warnings ;
> use strict ;


> my %priceHash ;
> my $zone = 5 ;
> my $weight = 5 ;


> lookupCost() ;


> #for $weight ( keys %priceHash ) {
> # print "$weight : " ;
> # for $zone ( keys %{$priceHash{$weight}} ) {
> # print "\t", $zone, "=", $priceHash{$weight}{$zone}, "\n" ;
> # }
> # print "\n" ;
> #}


> print "Price = ", $priceHash{$weight}{$zone}, "\n" ;


> sub lookupCost {
> open PRICES, "<", "/var/www/inhouse/pforce/pforcePrices.csv"
> or die "Cannot opne prices csv file: $!" ;


> my @lines = <PRICES> ;
> my $header = shift @lines ;
> chomp $header ;
> $header =~ s/\cM//g ; # MS CR/LF
> $header =~ s/zone//ig ;
> $header =~ s/\s+//g ;


> my @zones = split /,/ , $header ;
> shift @zones ; #first one is empty
> foreach ( @lines ) {
> chomp ;
> s/\cM//g ;
> my @prices = split /,/ ;
> my $kg = shift @prices ;


> foreach ( @zones ) {
> $priceHash{$kg}{$_} = shift @prices ;


Your problem is that you use floating point numbers as hash keys
and rely on some automatic conversion between strings and floating
point values.

In this line

$priceHash{$kg}{$_} = shift @prices ;

'$kg' will be a floating point number you just read from the file.
This could be e.g. "5.0" within the file but since floating point
numbers only have a limited precision the key in the hash could
actually be 4.9999999999 or 5.000000000001 or something similar.
So you end up with an element that has a key of e.g. 4.9999999999
and that, of course, won't be found when you look for an element
by the number 5 as the key. One way around that could be to use
double quotes arount the '$kg' to avoid conversion to a floating
point number, so the key isn't whatever approximation you have
for 5.0 but the string "5.0". Of course, to retrieve values from
the hash you will also need strings, not floating point numbers
and they must fit exactly what you used when you created the
hash, so you must use "5.0" and not "5" as the key.

But I would strongly recommend that you avoid anything related
to floating point numbers as keys. It's going to be extremely
hard to get right and there must be better ways to create keys
for your hash.
Regards, Jens
--
\ Jens Thoms Toerring ___ http://www.velocityreviews.com/forums/(E-Mail Removed)
\__________________________ http://toerring.de
 
Reply With Quote
 
Justin C
Guest
Posts: n/a
 
      05-01-2007
In article <CNKZh.7221$(E-Mail Removed). net>, Mumia W. wrote:
> On 05/01/2007 10:39 AM, Justin C wrote:
>> I can't seem to access the values in a hash of hashes, but if I iterate
>> over it I'm able to print all the values. The error I get if I try to
>> access one value is :
>> Use of uninitialized value in print at ./test line 20, <PRICES> line 62.
>> [...]

>
> Your program is so close to working, but you have one problem--you
> forgot that hash keys are strings and only strings. Where string
> comparisons are concerned, '5' != '5.0'. Change $weight (at the top of
> the program) to "5.0" and rerun your program.


Hash keys are strings! Of course! Thank you for pointing this out, I'd
been staring at it for hours and just could not see it.


> However, it's better to create the hash keys as simpler numbers, e.g.
> insert 5 rather than 5.0:
>
> $priceHash{$kg+0}{$_} = shift @prices;


I don't understand what's going on here. $kg is a string, the string is
"5.0", yet "$kg+0" removes ".0". Please tell me what's going on, it's
confusing and my brain is already a little bruised from today's work!


> This causes a warning about "per" which has some function in your data
> that I don't know about.


Ah, yes, I need to skip that line too, I'll fix my script to ignore it.


> I also have two minor nickpicks: "open" is misspelled in the die()
> statement,


That *is* a nit pick!


> and the PRICES file is never explicitly closed by program.


I'm sure I read here that file-handles are closed automatically when
they go out of scope, I've not bothered closing a file since. Is this
bad?


> You also do a little more work than is necessary to read in the data.


I know, I don't do anywhere near enough perl to be proficient, though I
am trying!


> This is a shorter version of your program:

[snip]

Lots of better ways of doing things. Thank you for pointing them out.

Justin.

--
Justin C, by the sea.
 
Reply With Quote
 
John W. Krahn
Guest
Posts: n/a
 
      05-01-2007
Jens Thoms Toerring wrote:
>
> Your problem is that you use floating point numbers as hash keys
> and rely on some automatic conversion between strings and floating
> point values.
>
> In this line
>
> $priceHash{$kg}{$_} = shift @prices ;
>
> '$kg' will be a floating point number you just read from the file.
> This could be e.g. "5.0" within the file but since floating point
> numbers only have a limited precision the key in the hash could
> actually be 4.9999999999 or 5.000000000001 or something similar.
> So you end up with an element that has a key of e.g. 4.9999999999
> and that, of course, won't be found when you look for an element
> by the number 5 as the key.


No, that is not correct. The data is read from the file and stored in Perl's
scalars as strings and is not converted to a floating point number because it
is not used in any mathematical operations.


John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
 
Reply With Quote
 
John W. Krahn
Guest
Posts: n/a
 
      05-01-2007
Mumia W. wrote:
> On 05/01/2007 10:39 AM, Justin C wrote:
>> I can't seem to access the values in a hash of hashes, but if I iterate
>> over it I'm able to print all the values. The error I get if I try to
>> access one value is :
>> Use of uninitialized value in print at ./test line 20, <PRICES> line 62.
>> [...]

>
> Your program is so close to working, but you have one problem--you
> forgot that hash keys are strings and only strings. Where string
> comparisons are concerned, '5' != '5.0'. Change $weight (at the top of
> the program) to "5.0" and rerun your program.
>
> However, it's better to create the hash keys as simpler numbers, e.g.
> insert 5 rather than 5.0:
>
> $priceHash{$kg+0}{$_} = shift @prices;
>
> This causes a warning about "per" which has some function in your data
> that I don't know about.
>
> I also have two minor nickpicks: "open" is misspelled in the die()
> statement, and the PRICES file is never explicitly closed by program.
> You also do a little more work than is necessary to read in the data.
>
> This is a shorter version of your program:
>
> use strict;
> use warnings;
> use File::Slurp;
>
> my %priceHash;
> my $weight = 5;
> my $zone = 5;
>
> my @lines = read_file('pforcePrices.csv');
> s/\cM\cJ$// for @lines;
>
> my $header = shift @lines;
> $header =~ s/(zone|\s+|^,)//ig;
> my @zones = split /,/,$header;
>
> foreach my $line (@lines) {
> next unless $line =~ /^\d/;
> my @prices = split /,/,$line;
> my $kg = shift @prices;
> foreach my $zn (@zones) {
> $priceHash{$kg+0}{$zn} = shift @prices;
> }
> }
>
> print "Price: $priceHash{$weight}{$zone}\n";


I'd do it more like this instead:

open my $PRICES, '<', 'pforcePrices.csv'
or die "Cannot open 'pforcePrices.csv' $!";

( my $header = <$PRICES> ) =~ s/\s+\z//;
my ( undef, @zones ) = map { s/\s*zone\s*//i; $_ } split /,/ , $header;

my %priceHash;
while ( <$PRICES> ) {
s/\s+\z//;
my ( $kg, @prices ) = split /,/;
@{ $priceHash{ $kg } }{ @zones } = @prices;
}




John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
 
Reply With Quote
 
Martien verbruggen
Guest
Posts: n/a
 
      05-01-2007
On Tue, 01 May 2007 19:49:46 -0000,
Justin C <(E-Mail Removed)> wrote:
> In article <CNKZh.7221$(E-Mail Removed). net>, Mumia W. wrote:
>> On 05/01/2007 10:39 AM, Justin C wrote:


>> However, it's better to create the hash keys as simpler numbers, e.g.
>> insert 5 rather than 5.0:
>>
>> $priceHash{$kg+0}{$_} = shift @prices;

>
> I don't understand what's going on here. $kg is a string, the string is
> "5.0", yet "$kg+0" removes ".0". Please tell me what's going on, it's
> confusing and my brain is already a little bruised from today's work!


$kg + 0 is an arithmetic expression, which perl calculates. The result
of it is a number (not a string). That number happens to be 5. The
number then gets stringified, because it is used as a hash key, and the
result is "5". There is a lot of stuff going on behind the scenes, which
has to do with the way Perl's scalars can represent all these different
things like strings, integers, doubles, references, etc.

Watch:

$ perl -w
my $a1 = 5.0;
my $a2 = "5.0";
print "$a1 $a2\n";
$a2 += 0;
print "$a1 $a2\n";
__END__
5 5.0
5 5

Generally, if you want numbers to be stringified in a particular format
you should use (s)printf.

Martien
--
|
Martien Verbruggen | We are born naked, wet and hungry. Then
| things get worse.
|
 
Reply With Quote
 
Tad McClellan
Guest
Posts: n/a
 
      05-01-2007
Justin C <(E-Mail Removed)> wrote:
> In article <CNKZh.7221$(E-Mail Removed). net>, Mumia W. wrote:


>> and the PRICES file is never explicitly closed by program.

>
> I'm sure I read here that file-handles are closed automatically when
> they go out of scope,



That is correct.


> I've not bothered closing a file since.



perl will always do what it is supposed to do, it is a machine...


> Is this
> bad?



.... but that does not lead to the conclusion that the human telling
perl what to do will do what _it_ is supposed to.

See my tale of woe from leaving out a close():

http://groups.google.com/group/comp....d4587743c64e2f


--
Tad McClellan SGML consulting
(E-Mail Removed) Perl programming
Fort Worth, Texas
 
Reply With Quote
 
Justin C
Guest
Posts: n/a
 
      05-02-2007
On 2007-05-01, Tad McClellan <(E-Mail Removed)> wrote:
> Justin C <(E-Mail Removed)> wrote:
>> In article <CNKZh.7221$(E-Mail Removed). net>, Mumia W. wrote:

>
>>> and the PRICES file is never explicitly closed by program.

>>
>> I'm sure I read here that file-handles are closed automatically when
>> they go out of scope,

>
>
> That is correct.
>
>
>> I've not bothered closing a file since.

>
>
> perl will always do what it is supposed to do, it is a machine...
>
>
>> Is this
>> bad?

>
>
> ... but that does not lead to the conclusion that the human telling
> perl what to do will do what _it_ is supposed to.
>
> See my tale of woe from leaving out a close():
>
> http://groups.google.com/group/comp....d4587743c64e2f


OK, point taken. Explicit close() added... now to grep the rest of what
I'd written and see how many have more open()s than close()s

Justin.

--
Justin C, by the sea.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
hash of hash of hash of hash in c++ rp C++ 1 11-10-2011 04:45 PM
"Pseudo-hashes are deprecated" error and accessing a hash of hashes ernestm@mindspring.com Perl Misc 3 01-31-2006 04:40 AM
Hash of hashes, of hashes, of arrays of hashes Tim O'Donovan Perl Misc 5 10-28-2005 05:59 AM
Hashes of hashes or just one hash ? Perl Learner Perl Misc 11 06-09-2005 06:55 AM
Performance Improvement of complex data structure (hash of hashes of hashes) Scott Gilpin Perl Misc 2 08-26-2004 01:02 AM



Advertisments