[newbie] printing a hash

D

David

I can't really visualise what's going on in this code. We're simply reading
splitting each line of a file and saving the result in a hash, right?

How can I print the contents of the hash?

open(FILE, 'orig.txt') or die "Can't open orig.txt: $!";

my @fields = qw/a b c d e f g h i j k/;
my $record = <FILE>;

while (<FILE>) {
chomp $record;
my %hash;
@hash{@fields} = split(/\t/, $record);
}

print "$. records processed.\n";

close FILE;
 
T

Tassilo v. Parseval

Also sprach David:
I can't really visualise what's going on in this code. We're simply reading
splitting each line of a file and saving the result in a hash, right?

How can I print the contents of the hash?

open(FILE, 'orig.txt') or die "Can't open orig.txt: $!";

my @fields = qw/a b c d e f g h i j k/;
my $record = <FILE>;

while (<FILE>) {
chomp $record;
my %hash;
@hash{@fields} = split(/\t/, $record);
}

This makes no sense. You read the first record from FILE into $record
and then loop over the rest of the file, but without ever assigning the
next record to $record. The above should read:

# drop this:
# my $record = <FILE>;

while (<FILE>) {
chomp;
my %hash;
@hash{ @fields } = split /\t/, $_;
# do something with %hash now as
# it will be recreated each
# iteration
}
print "$. records processed.\n";

close FILE;

Tassilo
 
B

Beable van Polasm

David said:
I can't really visualise what's going on in this code. We're simply
reading splitting each line of a file and saving the result in a
hash, right?

Yep. The hash keys are the letters [a-k], and the hash values are the
fields from a line the file. The fields in the file are separated by
tabs.
How can I print the contents of the hash?

open(FILE, 'orig.txt') or die "Can't open orig.txt: $!";

my @fields = qw/a b c d e f g h i j k/;

These next two lines appear to be slightly wrong:
my $record = <FILE>;

Delete the above line, and...
while (<FILE>) {

change the above line to:

while (my $record = <FILE>) {

That way, $record will be updated every time around the loop, instead
of only once before the loop.
chomp $record;
my %hash;
@hash{@fields} = split(/\t/, $record);

# print the hash
my @keys = keys %hash;
foreach my $key (@keys) {
print("key: $key => value: $hash{$key}\n");
}
print("-" x 72, "\n");
}

print "$. records processed.\n";

close FILE;


--
 
I

Iain

I can't really visualise what's going on in this code. We're simply
reading splitting each line of a file and saving the result in a
hash, right?

How can I print the contents of the hash?

As you will no doubt learn very rapidly if you read this group, you
ought to start every Perl program with the incantation:

use strict;
use warnings;

which allows Perl to help you by spitting out lots of useful information
about possible mistakes in your program.
open(FILE, 'orig.txt') or die "Can't open orig.txt: $!";

my @fields = qw/a b c d e f g h i j k/;
my $record = <FILE>;

<> in scalar context returns a single line from a file, so this will
read the first line of the contents of FILE into $record. It's not
really necessary in this instance (see below).
while (<FILE>) {

Whereas <> as the sole condition for a while loop is magic, and is
shorthand for:

while ( $_ = <FILE> ) {

So in this case I suspect you would be better off with the condition

while ( my $record = <FILE> ) {

chomp $record;

This will work the first time around the loop, but in your original
program you're not updating the value of $record anywhere, making it a
fairly worthless statement.
my %hash;

You are using my() within a block (the {..} construct of the while
loop). This will lexically scope the variable to a *single iteration* of
the loop. In other words, you are creating a new %hash variable every
time you read another line from FILE. And losing it almost immediately.
Do you really want a new hash for each line of the file, or are you
trying to aggregate the data in some form?
@hash{@fields} = split(/\t/, $record);

You are trying to assign to a hash slice of exactly 11 keys. Is this
what you want -- in other words, can you guarantee that each line of
FILE contains 11 items each separated by a single tab character?
}

print "$. records processed.\n";

This works, but it's probably clearer to use an explicit line-counter
variable. That will also have the advantage that it won't get reset if
you close() the file.
close FILE;

And I haven't yet touched upon how you might view the contents of your
hash, but see the following. Note that it probably isn't doing what you
expect or want (unles you really DO want the hash to be overwritten on
each iteration), but it should give you a clearer idea of what's going
on.



#!perl

use strict;
use warnings;

open(FILE, 'orig.txt') or die "Can't open orig.txt: $!";

my @fields = qw/a b c d e f g h i j k/;

my $lines = 0;
while (my $record =<FILE>) {
chomp $record;
my %hash;
@hash{@fields} = split(/\t/, $record);
$lines++;

print "After $lines lines, hash contains:\n";
# A simple way to print the contents of a hash:
foreach ( sort keys %hash ) {
print " $_ => $hash{$_}\n";
}

}

close FILE;
print "$lines records processed.\n";
 
T

Tad McClellan

Iain said:
Whereas <> as the sole condition for a while loop is magic, and is
shorthand for:

while ( $_ = <FILE> ) {


It is actually shorthand for:

while ( defined($_ = <FILE>) ) {
 
T

Tad McClellan

David said:
I can't really visualise what's going on in this code.

my @fields = qw/a b c d e f g h i j k/; [snip]
@hash{@fields} = split(/\t/, $record);


I'll guess that this is what is throwing you (despite the many
other problems in your program).

That is a "hash slice". Read all about it in the "Slices" section of:

perldoc perldata
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top