计数发生计数中的元素

问题描述 投票:1回答:2

这里我得到一个包含一些主题结果的文本文件。在Perl中进行如下计数表的可能方法是什么?

result.txt

Math Peter pass
English Peter pass
Music Peter fail
Science Peter fail
Art Mary fail
Music Mary fail
English Mary fail
Math Bob pass
English Bob fail
Art Bob pass
Music Bob fail
English Mike pass
Science Mike pass

Output

name    pass    fail
Peter   2   2
Mary    0   3
Bob 2   2
Mike    2   0

我已经尝试过这个并且可以成功地以吐出的形式打印转储

#!/usr/bin/perl

use strict;

use Data::Dumper;

my $CurrentPath = "/tmp";

open(FILE, "/tmp/result.txt") or die("Cannot open file result.txt for reading: $!");
my @results = <FILE>;
s{^\s+|\s+$}{}g foreach @results;
close FILE;

my @data_split = ();

foreach my $result ( @results ) {
    push @data_split, [ split /\s+/, $result ];
}

print Dumper \@data_split;

1;

output

$VAR1 = [
          [
            'Math',
            'Peter',
            'pass'
          ],
          [
            'Eng',
            'Peter',
            'pass'
          ],
          ...............
perl
2个回答
2
投票

要计算和管理一系列项目以及任何结构化信息,哈希非常有用。使用它们和数组,您可以通过引用构建可以编码相当复杂关系的数据结构。见perldsc。一旦这些变得笨拙,下一步就是写一堂课。

它可以沿着这些方向发展

use warnings;
use strict;
use feature 'say';   
use Data::Dump qw(dd);

my $file = shift @ARGV;
die "Usage: $0 filename\n" if not $file;

open my $fh, '<', $file or die "Can't open $file: $!";

my %results;

while (<$fh>) {
    next if not /\S/;  # skip empty lines

    my ($subj, $name, $grade) = split;

    if (not $subj or not $name or not defined $grade) {
       warn "Incomplete data, line: $_";
       next;
    }

    if ($grade eq 'pass') {
        $results{$name}->{pass}++;
    }  
    elsif ($grade eq 'fail') {
        $results{$name}->{fail}++;
    }  
    else { 
        warn "Unknown grade format for $name in $subj: $grade";
        next;
    }
}
dd \%results;

没有单个出现特定分数的名称保持不具有该分数的hashref。例如,如果您需要这些条目,则后处理%results以添加它们

foreach my $name (keys %results) {
    $results{$name}->{pass} = 0 if not exists $results{$name}->{pass};
    $results{$name}->{fail} = 0 if not exists $results{$name}->{fail};
}

或者,添加一个语句来初始化代码中每个记录(名称)的两个分数。

请注意,我们可以扩大此数据结构以存储更多信息(例如$subj),因为需要,干净利落且代码更改很少。这是使用哈希的另一个好处。

关于发布的代码的一些评论

  • 为什么一开始没有use warnings;?你必须拥有它;它直接有用
  • 使用lexical filehandle,qazxsw poi而不是globes(qazxsw poi)
  • 除非有特定原因要先读取整个内容,否则一次处理一行文件
  • 你总是希望根据你的预期来检查输入;究竟是什么取决于你的问题和设计。在上面的代码中,所有字段必须定义且合理(等级允许为0),而您实际上可能接受不存在的等级;适当调整。 当然,如果该程序读取的所有文件都与您显示的一样,总是包含所有字段并且只有通过/未通过等级,那么就不需要检查输入
  • open my $fh, '<', $file ...中的模式FILE应该几乎总是被/\s+/取代,这是相同的,但它也丢弃了前导空间。它也是默认值,与字符串的split一起,因此只是上面的' '(由$_分割的字符串是split;
  • 您可以构建一个类似于此处使用的数据结构以及您获得的数据结构。但是我没有看到数组数组的好处

可以更简洁地写出适当计数器的增量

' '

如果您宁愿让代码在第三个字段中悄悄地接受任何内容并将其存储在$_中,并将其计入while (<$fh>) { next if not /\S/; my ($subj, $name, $grade) = split; # check input ... if ($grade !~ /^(?:pass|fail)$/) { warn "Unknown grade format for $name in $subj: $grade"; next; } $results{$name}->{$grade}++; }


-1
投票

这是一个非常基本的解决方案,不会检查输入数据。它将每个哈希值初始化为%results,以便没有需要默认的“缺失”值

请注意,Perl哈希是无序的,因此输出的顺序也是不确定的。如果您需要任何具体的信息,那么您必须这样说

pass|fail

output

{ pass => 0, fail => 0 }
© www.soinside.com 2019 - 2024. All rights reserved.