我有多列的制表符分隔数据。
我在第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
但是这段代码中似乎有一些错误,因为我得到的结果值并不像预期的那样。
我做错了什么?
答案 0 :(得分:6)
看起来你实际上并没有添加计数 - 你用该操作系统最后一行的计数覆盖任何操作系统的最后一次计数。
$count{$line[30]} = $line[5] + $line[6];
应该是
$count{$line[30]} += $line[5] + $line[6];
作为可以改善整体代码但不影响其正确性的其他注意事项:
请使用3参数形式的open和Lexical文件句柄:
open(my $filehandle, "<", $f) || die "Cannot open $f: $!";
如果您100%确定您的文件在字段内容中不包含带引号的字段值或标签,那么基于split
的逻辑就可以了。对于非常复杂的X分隔文件,我强烈建议您使用Text::CSV_XS
/ Text::CSV
CPAN模块
不需要初始化%count
或$w
变量 - 哈希将自动初始化为空哈希,$w
被分配为循环变量 - 您可能希望实际上在循环中声明它:foreach my $w (sort keys %count) {
请不要使用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}}
答案 2 :(得分:2)
$count{$line[30]} = $line[5] + $line[6];
应该使用+ =运算符将行的总和添加到总计,而不是将设置为总计:
$count{$line[30]} += $line[5] + $line[6];