【问题标题】:Push to array not working inside loop推送到数组在循环内不起作用
【发布时间】:2013-07-30 15:13:08
【问题描述】:

目标:

我正在尝试计算文本文件中“列”20 中的值,然后使用文本文件中行中的值打印出现次数。除了“列”0(第一列)之外,有些行是相同的。我正在尝试使用哈希(尽管我对如何使用哈希的理解有限)。

问题:

在子函数中(在 foreach 循环内)执行 push 时,值不会被推送到循环外的数组中,因此输出不会保存到文件中。在循环内部打印(打印 $dummy)并且所有数据都被显示。

输入:

Filename1 Value1a Value2a Value3a ... Column20a ... ColumnENDa
Filename2 Value1b Value2b Value3b ... Column20b ... ColumnENDb
Filename3 Value1c Value2c Value3c ... Column20a ... ColumnENDc
...

输出(在循环内使用 print $dummy):

2 Column20a Filename1, Filename3
1 Column20b Filename2
...

代码:

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

为什么 push 函数在 sub(foreach 循环)之外不起作用?

【问题讨论】:

  • 感谢您删除标题中的“标签”Perl:@Micha。不过,我在问题旁边看到的 10 个相关主题中有 9 个在标题中带有 Perl 标签。但是,我会尊重“规则”并尽量将标签放在标题之外,即使我不明白其中的危害。 :)
  • 感谢您的理解。没有冒犯的意思。 “我在问题旁边看到的 10 个相关主题中有 9 个在标题中有标签 Perl” - 嗯,是的,你的权利,问题是 SO 有一个功能良好的标签系统,所以标题中的标签是不必要的,而且它们使标题更复杂/令人困惑,然后是必要的。所以一个标签可能不是问题,但它 - 不仅在我看来 - 一个原则性的东西。

标签: perl hash foreach push


【解决方案1】:

你实际上并没有打电话给你的潜艇。

如果您的意思是 END block,它不应该是子 - 并且您不应该使用 END 块,除非有技术原因这样做。

如果您的意思是它是一个子,则将其命名为其他名称并实际调用它(名称不是错误,只是看起来很糟糕 - END 具有特殊含义)。 p>

您的代码的结尾将是(不修复/改进它):

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);
    }
}

作为替代方案,甚至没有 sub(几行代码就没有必要了 :)

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

我在您自己的代码版本上对此进行了测试,并使用您的测试输入在输出文件中获得了以下内容:

Counts  Name    File_names
2        Column20a       Filename1,Filename3
1        Column20b       Filename2

【讨论】:

    【解决方案2】:

    为什么要在 foreach 循环中编写子程序?因此,对于循环中的每次迭代,您都会创建一个新的。 你子程序的名称也有问题。其实你不叫它。而且你不能调用它,因为 perl 使用 END 作为 END 块。让我用一个例子来告诉你:

    use warnings;
    use strict;
    
    END('hello world');
    
    sub END{
        my $string = shift;
    
        print $string;
    }
    

    END 块的目的是在程序结束时执行括号之间的所有操作,因此是名称。

    use warnings;
    use strict;
    
    END('hello world');
    
    sub END{
        my $string = shift;
    
        print $string;
    }
    

    要么省略子例程,要么在全局上下文中声明它,例如在程序结束时。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-29
      • 1970-01-01
      • 2016-05-18
      相关资源
      最近更新 更多