0

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)?

2
  • Thanks for removing the "tag" Perl: in the title @Micha. Though, 9 of the 10 related topics I see next to my question have the tag Perl in the title. However, I will respect the "rules" and try to keep tags out of the title, even though I don't understand the harm. :) Commented Jul 30, 2013 at 18:49
  • Thanks for your understanding. No offense meant. "9 of the 10 related topics I see next to my question have the tag Perl in the title" - well, yes your right, problem is that SO has a well function tag system and so tags in title are needless and moreover they make the title more complex/confusing then necessary. So one tag may not be the problem but its a - not only in my eyes - a principle thing. Commented Jul 31, 2013 at 5:00

2 Answers 2

1

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
Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.