Perl在while循环中读取文件,然后尝试在foreach循环中添加月份数据

Perl在while循环中读取文件,然后尝试在foreach循环中添加月份数据,perl,controls,while-loop,flow,Perl,Controls,While Loop,Flow,我正在读取一个空格分隔的文本文件,并尝试根据月份添加数据,数据如下所示: my %sum; while (<>) { # instead of open on @ARGV, just use diamond operator my ($day, $month, $date, $time, $gmt, $year, $volt, $amp, $pf, $watt, $voltamp) = split; $sum{"$year$month"}{'vol

我正在读取一个空格分隔的文本文件,并尝试根据月份添加数据,数据如下所示:

my %sum;
while (<>) {  # instead of open on @ARGV, just use diamond operator
    my ($day, $month, $date, $time, $gmt, $year, $volt, $amp, 
        $pf, $watt, $voltamp) = split;
    $sum{"$year$month"}{'voltamp'} += $voltamp;
    $sum{"$year$month"}{'watt'} += $watt;
    ....
}
2011年4月4日星期一08:00:00 MDT 120.72 0.30.707 25.609 25.609

2011年4月4日星期一07:45:00 MDT 119.94 0.30.707 25.443 25.443

我只是想把每月的总数加起来:

#!/usr/bin/perl 

use strict;
use warnings;
use diagnostics;
use vars;

my $line;
my @data;
my @months;

my ($day, $month, $date, $time, $gmt, $year, $volt, $amp, $pf, $watt, $voltamp, 
    $voltsum, $wattsum, $count, $months, $monthlytotal );

$voltsum = 0;
$wattsum = 0;

open(DATAFILE, "@ARGV") ||  die $!;

@months = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );

            while (<DATAFILE>) {
            $line = $_;
            chomp $line;
            @data = split(/\s/,$line);
            $day = $data[0];
            $month = $data[1];
            $date = $data[2];
            $time = $data[3];
            $gmt = $data[4];
            $year = $data[5];
            $volt = $data[6];
            $amp = $data[7];
            $pf = $data[8];
            $watt = $data[9];
            $voltamp = $data[10];

使用模块解析时间戳可能会使您受益匪浅。但是,一个简单的修复方法可能是执行以下操作:

my %sum;
while (<>) {  # instead of open on @ARGV, just use diamond operator
    my ($day, $month, $date, $time, $gmt, $year, $volt, $amp, 
        $pf, $watt, $voltamp) = split;
    $sum{"$year$month"}{'voltamp'} += $voltamp;
    $sum{"$year$month"}{'watt'} += $watt;
    ....
}

以下数据结构可能更合适()


如果你想让它流线化——就像你的程序看起来一样——假设你的数据是经过排序的,你应该首先引入一个变量来检查月份,它由月份+年份组成。这样更安全(2011年4月不是2012年4月)

  • 初始化“上次检查的月份”
  • 需要时初始化求和并求和
  • 到打印时间时打印
可能看起来像:

my $last_month;

print "Month  Year Watts     Vars\n";
print "--------------------------\n";
while (<DATAFILE>) {
    # ... snip
    $voltamp = $data[10];

    my $current_month = $month . ' ' . $year; # Apr 2011 != Apr 2012
    if (!defined $last_month || $current_month ne $last_month) {
        # month changed
        if (defined $last_month) {
            # print intermediate sum
            print "$last_month $wattsum $voltsum\n";
        }
        $last_month = $current_month;
        $voltsum = 0;
        $wattsum = 0;
    }
    $voltsum += $voltamp;
    $wattsum += $watt;
}
print "$last_month $wattsum $voltsum\n"; # print last sum
my$last\u月;
打印“月-年瓦特变量\n”;
打印“-----------------------------------\n”;
而(){
#…剪断
$voltamp=$data[10];
我的$current_month=$month.'.$year;#2011年4月!=2012年4月
如果(!定义的$last|u month |$current|u month ne$last|u month){
#月变
如果(定义为$last_月){
#打印中间和
打印“$last_month$wattsum$voltsum\n”;
}
$last_month=$current_month;
$voltsum=0;
$wattsum=0;
}
$voltsum+=$voltamp;
$wattsum+=$watt;
}
打印“$last_month$wattsum$voltsum\n”#打印最后一笔金额

然而,我也更喜欢用散列来总结,比如写这篇文章时出现的最近两个答案,所以我跳过了第二个解决方案。

您可能希望使用模块来解析日期,而不是依赖于拆分。谢谢,这非常有效,如果其他人遇到这一点,这里有一个关于散列的优秀教程@AndrewScrivner如果您觉得这是您问题的正确答案,您可以通过单击旁边的复选标记来接受它。快速提问,是否可以在不使用临时变量的情况下将$sum{$month}{'watt}放入printf?我使用了一个temp$wph=$sum{$month}{'watt'};要实现这一点:printf(“%.2f\n”,$wph);有更好的方法吗?@AndrewScrivner我认为printf“%.2f\n”、$sum{$month}{'watt}没有什么错。为什么会有?我也不这么认为,在测试中,它工作正常,我一定是有语法错误导致我误入歧途。这同样有效,并帮助我理解了我遇到的流量控制问题,非常感谢!非常感谢,这也非常有用!;)
use warnings;
use strict;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;

my %sums;
while (<DATA>) {
    my @tokens = split;
    $sums{$tokens[1]}{volt   } += $tokens[6];
    $sums{$tokens[1]}{amp    } += $tokens[7];
    $sums{$tokens[1]}{pf     } += $tokens[8];
    $sums{$tokens[1]}{watt   } += $tokens[9];
    $sums{$tokens[1]}{voltamp} += $tokens[10];
}

print Dumper(\%sums);

__DATA__
Mon Apr 04 08:00:00 MDT 2011 120.72 0.3 0.707 25.609 25.609
Mon Apr 04 07:45:00 MDT 2011 119.94 0.3 0.707 25.443 25.443
$VAR1 = {
          'Apr' => {
                     'amp' => '0.6',
                     'pf' => '1.414',
                     'volt' => '240.66',
                     'voltamp' => '51.052',
                     'watt' => '51.052'
                   }
        };
my $last_month;

print "Month  Year Watts     Vars\n";
print "--------------------------\n";
while (<DATAFILE>) {
    # ... snip
    $voltamp = $data[10];

    my $current_month = $month . ' ' . $year; # Apr 2011 != Apr 2012
    if (!defined $last_month || $current_month ne $last_month) {
        # month changed
        if (defined $last_month) {
            # print intermediate sum
            print "$last_month $wattsum $voltsum\n";
        }
        $last_month = $current_month;
        $voltsum = 0;
        $wattsum = 0;
    }
    $voltsum += $voltamp;
    $wattsum += $watt;
}
print "$last_month $wattsum $voltsum\n"; # print last sum