在Perl中计算另一列中每个值的总和w.r.t.

时间:2011-02-17 23:08:31

标签: perl parsing

我有多列的制表符分隔数据。

我在第31列有操作系统名称,在第6和第7列有数据字节。我想要做的是计算每个唯一操作系统的总容量。

所以,我在Perl中做了这样的事情:

#!/usr/bin/perl
use warnings;

my @hhfilelist  = glob "*.txt";
my %count = ();

for my $f (@hhfilelist) {
    open F, $f || die "Cannot open $f: $!";
    while (<F>) {
        chomp;
        my @line = split /\t/;
        # counting volumes in col 6 and 7 for 31
        $count{$line[30]} = $line[5] + $line[6];     
    }
    close (F);
}

my $w = 0;

foreach $w (sort keys %count) {
    print "$w\t$count{$w}\n";
}

因此,结果将类似于

Windows    100000
Linux        5000
Mac OSX     15000
Android      2000

但是这段代码中似乎有一些错误,因为我得到的结果值并不像预期的那样。

我做错了什么?

3 个答案:

答案 0 :(得分:6)

看起来你实际上并没有添加计数 - 你用该操作系统最后一行的计数覆盖任何操作系统的最后一次计数。

$count{$line[30]} = $line[5] + $line[6];

应该是

$count{$line[30]} += $line[5] + $line[6];

作为可以改善整体代码但不影响其正确性的其他注意事项:

  1. 请使用3参数形式的open和Lexical文件句柄:

     open(my $filehandle, "<", $f) || die "Cannot open $f: $!";
    
  2. 如果您100%确定您的文件在字段内容中不包含带引号的字段值或标签,那么基于split的逻辑就可以了。对于非常复杂的X分隔文件,我强烈建议您使用Text::CSV_XS / Text::CSV CPAN模块

  3. 不需要初始化%count$w变量 - 哈希将自动初始化为空哈希,$w被分配为循环变量 - 您可能希望实际上在循环中声明它:foreach my $w (sort keys %count) {

  4. 请不要使用1个字母的变量。 $w在最后一个循环中没有意义,而$os_name是明确的。

答案 1 :(得分:3)

你的表达

open F, $f || die "Cannot open $f: $!";

有一个微妙的错误,最终会咬你,但可能不是今天。

||运算符的优先级高于其左侧的逗号运算符,因此该表达式实际上被解析为

open F, ($f || die "Cannot open $f: $!")

也就是说,当die有假(0,$f"")值时,undef open $f语句无法使用open (F, $f) || die ... 指定的名称打开文件。

要做你的意思,你可以使用括号:

or

或使用备用低优先级open F, $f or die ... 运算符

{{1}}

At times I have been bitten by this myself

答案 2 :(得分:2)

$count{$line[30]} = $line[5] + $line[6];

应该使用+ =运算符将行的总和添加到总计,而不是将设置为总计:

$count{$line[30]} += $line[5] + $line[6];