Having Trouble Accessing Hash with Two "keys"

R

R^3

For some reason, I cannot access a hash with two keys. When I attempt
to print its contents, all I get is whitespace.

If I try to print "$counts{'french',4}"; I get the proper output, but
when I try "$counts{$building,$i}; all I get is whitespace. How can I
fix this????

#!/usr/bin/perl

open (OUT,">data.dat");

my %hash = ();
@masterBuildings = ();
while ($line = <STDIN>)
{
if ($line =~ m/\(Info\): Station (\w+) (Rea|A)ssociated/){
@fields = split " ", $line;
$index = $fields[2];
$building = $fields[5];
$building =~ s/[0-9]+-(wb|ap)$//;
$counts{$building,$index} += 1;
push(@masterBuildings,$building);
}

}
@Buildings = &uniq(@masterBuildings);

foreach $building (@Buildings) {
#$building = "'" . $building . "'";
$i = 2;
while ($i < 7) {
print "$counts{$building, $i}\n";
#does not work, but $counts{'french',4} does.
$i += 1;
}
}


sub uniq {
local(@words) = @_; # local copy of array
local(%MARK); # temporary associative array
grep($MARK{$_}++, @words); # counts each occurance
(ignored)
keys %MARK; # return the unique elements

}
 
T

Toni Erdmann

R^3 said:
For some reason, I cannot access a hash with two keys. When I attempt
to print its contents, all I get is whitespace.

If I try to print "$counts{'french',4}"; I get the proper output, but
when I try "$counts{$building,$i}; all I get is whitespace. How can I
fix this????

You're using a hash with one key that consists of two strings.

try: $counts{'french'}{'4'}

Toni
 
B

Brian McCauley

R^3 said:
For some reason, I cannot access a hash with two keys.

Could that be because there's no such thing in Perl?

I Perl there are two ways to emmulate multi-keyed associative arrays.

Method 1 (from Perl4) join the keys using a non-printing character as a
delimiter. (This is what you've done).

Method 2 (usually the preferred method in Perl5) use a hash of
references to anonymous hashes. This is often abberviated to
hash-of-hash or HoH.

Are you using Perl5? Everything about your code seems to imply you have
written it to run on Perl4. Appart that is for one line with a "my" in
it that implies you must have Perl5.
When I attempt
to print its contents, all I get is whitespace.

Do you? Are you sure?
If I try to print "$counts{'french',4}"; I get the proper output, but
when I try "$counts{$building,$i}; all I get is whitespace.

Whitespace is not the same thing as nothing. Whitespace is a string
made up from spaces, tabs, carriage returns, linefeeds and formfeeds.
How can I
fix this????

#!/usr/bin/perl

open (OUT,">data.dat");

You forgot to check that succeded.
my %hash = ();

There's no need to explicitly make agregates empty - they start out that
way. Why do you delare a variable you never use?
@masterBuildings = ();

There's no need to explicitly make agregates empty - they start out that
way. You forgot my() - if you'd put "use strict" at the top of your
script perl would have spotted this for you.
while ($line = <STDIN>)

You forgot my() - if you'd put "use strict" at the top of your script
perl would have spotted this for you.
{
if ($line =~ m/\(Info\): Station (\w+) (Rea|A)ssociated/){
@fields = split " ", $line;

You forgot my() - if you'd put "use strict" at the top of your script
perl would have spotted this for you.

It would probably been more readble to use capturing rather than split.
$index = $fields[2];

You forgot my() - if you'd put "use strict" at the top of your script
perl would have spotted this for you.
$building = $fields[5];

You forgot my() - if you'd put "use strict" at the top of your script
perl would have spotted this for you.
$building =~ s/[0-9]+-(wb|ap)$//;
$counts{$building,$index} += 1;

+=1 is more conventionally written ++
push(@masterBuildings,$building);
}

}
@Buildings = &uniq(@masterBuildings);

Why is there an & there? If you don't know what the & does then you
doen't want it.
foreach $building (@Buildings) {

You forgot my() - if you'd put "use strict" at the top of your script
perl would have spotted this for you.
#$building = "'" . $building . "'";
$i = 2;

You forgot my() - if you'd put "use strict" at the top of your script
perl would have spotted this for you.
while ($i < 7) {

It would be more conventional to write:

for my $i ( 2 .. 6 )
print "$counts{$building, $i}\n";
#does not work, but $counts{'french',4} does.

What reason do you have to suppose that $building ever has the value
'french'.

Perhaps you should insert a diagnostic:

print "<<<$building>>>\n";

It's always a good idea to print something on the end like this in case
there's any whitespace on the end of the value of $building.
$i += 1;
}
}


sub uniq {
local(@words) = @_; # local copy of array

You should not localize a global varialble when a lexcal variable would
do the job perfectly well.
local(%MARK); # temporary associative array

Avoid comments that contain no information.
grep($MARK{$_}++, @words); # counts each occurance
(ignored)

Do not use grep() or map() in a void context, use for. That's what
it's, er..., for:

$MARK{$_}++ for @words;
 
A

A. Sinan Unur

For some reason, I cannot access a hash with two keys. When I attempt
to print its contents, all I get is whitespace.

If I try to print "$counts{'french',4}"; I get the proper output, but

Could you please explain what $counts{'french', 4} means? I am not
familiar with the notation, and it seems to do something, but I am at
a loss as to why you cannot use $counts{french}{4}?

D:\Home\asu1\UseNet\clpmisc> cat tt.pl
#!/usr/bin/perl

use strict;
use warnings;

my %hash;
$hash{qw(a b)} = 1;
$hash{a}{b} = 1;

use Data::Dumper;
print Dumper \%hash;

D:\Home\asu1\UseNet\clpmisc> tt
$VAR1 = {
'a' => {
'b' => 1
},
'a?b' => 1
};
#!/usr/bin/perl

use strict;
use warnings;
open (OUT,">data.dat");

Always check the return value of open to see if it succeded. Also, why are
you opening this file? You don't use it below.
my %hash = ();
@masterBuildings = ();

You don't need to explicitly initialize these variables:

my (%hash, @masterBuildings);
while ($line = <STDIN>)

When you are posting here, please use the DATA file handle as described
in the posting guidelines for this group.
{
if ($line =~ m/\(Info\): Station (\w+) (Rea|A)ssociated/){
@fields = split " ", $line;
$index = $fields[2];
$building = $fields[5];
$building =~ s/[0-9]+-(wb|ap)$//;

You need to make a decision here: Are you going to parse based on a
regular expression or are you just going to split the input line?
Here, you first use a capturing regex, then proceed to split. Since
we don't know what your input looks like, it is very hard to comment
on what you are doing.

....
sub uniq {
local(@words) = @_; # local copy of array
local(%MARK); # temporary associative array
grep($MARK{$_}++, @words); # counts each occurance
(ignored)
keys %MARK; # return the unique elements

I seriously doubt you want to use local here:

<URL:http://perl.plover.com/FAQs/Namespaces.html>

Besides, it is far easier to write this in the following way:

sub unique_values { my %tmp = map { $_ => 1 } @_; keys %tmp; }

Of course, I would have used List::MoreUtils::uniq:

<URL:http://search.cpan.org/~vparseval/List-MoreUtils-0.16/lib/List/MoreUtils.pm>
 
A

A. Sinan Unur

Could that be because there's no such thing in Perl?

I Perl there are two ways to emmulate multi-keyed associative arrays.

Method 1 (from Perl4) join the keys using a non-printing character as
a delimiter. (This is what you've done).


Thank you for the explanation. I had not seen that before.

Sinan
 
R

R^3

Thanks. I tried to implement an HoH again, and this time I was able to
get it to work! Thanks!
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top