EA00 EA00 - 1 year ago 122
Perl Question

Perl - initialization of hash

I'm not sure how to correctly initialize my hash - I'm trying to create a key/value pair for values in coupled lines in my input file.

For example, my input looks like this:

@cluster t.18
46421 ../../../output###.txt/
@cluster t.34
41554 ../../../output###.txt/

I'm extracting the t number from line 1 (@cluster line) and matching it to output###.txt in the second line (line starting with 46421). However, I can't seem to get these values into my hash with the script that I have written.

use warnings;
use strict;

my $key;
my $value;
my %hash;

my $filename = 'input.txt';
open my $fh, '<', $filename or die "Can't open $filename: $!";

while (my $line = <$fh>) {
chomp $line;
if ($line =~ m/^\@cluster/) {
my @fields = split /(\d+)/, $line;
my $key = $fields[1];
elsif ($line =~ m/^(\d+)/) {
my @output = split /\//, $line;
my $value = $output[5];
$hash{$key} = $value;

Answer Source

It's a good idea, but your $key that is created in the if block is a local variable scoped to that block, masking the global $key. Inside the if block the symbol $key has nothing to do with the one you nicely declared upfront.

It goes out of scope as soon as if is done and does not exist outside the if block, even in the same interation, and certainly not the next time through. The global $key comes back after the if, being visible elsewhere in the loop, but is undefined since it has never been assigned to. The same goes for $value in the elsif block.

Just drop the declaration inside the loop and assign to those global variables, thus without my, so $key = ... and $value = ... and the hash will be assigned correctly.

Note -- this is about to how get that hash assignment right. I don't know how your actual data looks and whether the line is parsed correctly. Here is toy input.txt

@cluster t.1 
1111 ../../../output1.1.txt/
@cluster t.2 
2222 ../../../output2.2.txt/

I pick the 4th field instead of the 6th, $value = $output[3];, and add

print "$_ => $hash{$_}\n" for keys %hash;

after the loop. This prints

1 => output1.1.txt
2 => output2.2.txt

I am not sure whether this is what you want but the hash is built fine.