Reputation: 9
AIM:
I am trying to count a value in "column" 20 in a text file, then print the number of occurrences with the values from the line in the text file. Some of the lines will be identical, with the exception of "column" 0 (first column). I am trying to use hashes (though I have limited understanding of how to use hashes).
PROBLEM:
While doing push in a sub function (inside a foreach loop) the value is not being pushed to an array outside the loop, and hence the output will not be saved to file. Printing inside of the loop works (print $dummy) and all the data is being displayed.
INPUT:
Filename1 Value1a Value2a Value3a ... Column20a ... ColumnENDa
Filename2 Value1b Value2b Value3b ... Column20b ... ColumnENDb
Filename3 Value1c Value2c Value3c ... Column20a ... ColumnENDc
...
OUTPUT (using print $dummy inside loop):
2 Column20a Filename1, Filename3
1 Column20b Filename2
...
CODE:
use strict;
use warnings;
use Cwd;
use File::Find::Rule;
use File::Spec;
use File::Basename;
use Text::Template;
use File::Slurp;
use List::MoreUtils qw(uniq);
my $current_dir = cwd;
my @test_file = read_file ("test_file.txt");
my %count = ();
my %name = ();
my @test = "Counts\tName\tFile_names";
foreach (@test_file) {
chomp $_;
our(@F) = split('\t', $_, 0);
++$count{"$F[20] "};
$name{"$F[20] "} .= "$F[0]," if $F[20];
sub END {
foreach $_ (keys %name) {
$name{$_} =~ s/,$//;
my $dummy = "$count{$_}\t $_\t $name{$_}\n";
#print $dummy;
push (@test, $dummy);
}
};
}
print "@test";
write_file( 'test.txt', @test);
Why is the push function not working outside the sub (foreach loop)?
Upvotes: 0
Views: 3744
Reputation: 637
Why do you code the subroutine in the foreach-loop? So for every iteration through your loop you create a new one. There is also a problem with the name of you subroutine. Actually you don't call it. And you can't call it, because perl uses END for the END block. Let me show you this with an example:
use warnings;
use strict;
END('hello world');
sub END{
my $string = shift;
print $string;
}
The purpose of the END block is to do everything between the brackets when the program ends, therefore the name.
use warnings;
use strict;
END('hello world');
sub END{
my $string = shift;
print $string;
}
Either you omit the subroutine or you declare it in a global context e.g. at the end of the program.
Upvotes: 0
Reputation: 129393
You're not actually calling your sub.
If you meant it to be the END
block, it shouldn't be a sub - and you should not use END blocks unless there's a technical reason to do so.
If you mean it to be a sub, name it something else and actually call it (the name isn't an error, just looks bad - END
has special meaning).
The end of your code would be (without fixing/improving it):
foreach (@test_file) {
chomp $_;
our(@F) = split('\t', $_, 0);
++$count{$F[20]};
$name{$F[20]} .= "$F[0]," if $F[20];
}
process_test();
print "@test";
write_file( 'test.txt', @test);
##########################
sub process_test {
foreach $_ (keys %name) {
$name{$_} =~ s/,$//;
my $dummy = "$count{$_}\t $_\t $name{$_}\n";
push (@test, $dummy);
}
}
As an alternative, don't even have a sub (it's not necessary for a couple of lines of code :)
foreach (@test_file) {
chomp $_;
our(@F) = split('\t', $_, 0);
++$count{$F[20]};
$name{$F[20]} .= "$F[0]," if $F[20];
}
foreach $_ (keys %name) {
$name{$_} =~ s/,$//;
my $dummy = "$count{$_}\t $_\t $name{$_}\n";
push (@test, $dummy);
}
print "@test";
write_file('test.txt', @test);
I tested this on my own version of your code, and got the following in the output file using your test input:
Counts Name File_names
2 Column20a Filename1,Filename3
1 Column20b Filename2
Upvotes: 1