JamesT
JamesT

Reputation: 9

Push to array not working inside loop

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

Answers (2)

Nick Lehmann
Nick Lehmann

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

DVK
DVK

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

Related Questions