Perl читает файл в цикле while, затем пытается добавить данные за месяц в цикле foreach - PullRequest
2 голосов
/ 17 января 2012

У меня есть текстовый файл с разделителями-пробелами, который я читаю и пытаюсь добавить данные на основе месяца, данные выглядят так:

Пн Апр 04 08:00:00 MDT 2011 120.72 0.3 0.707 25.60925.609

Пн Апр 04 07:45:00 MDT 2011 119.94 0.3 0.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];

Я хочучтобы соответствовать месяцу, добавьте мои данные и напечатайте результат один раз, но мой контроль потока неверен, есть идеи, как это сделать правильно?

Я хочу прочитать каждую строку, проверить, какой это месяц,сложите все похожие месяцы вместе и верните результат.

    foreach $months(@months) { 
       if ( $months =~ $month  ) {
                  $voltsum += $voltamp;
                  $wattsum += $watt;
            print "$month $year $wattsum $voltsum\n";
    }
            elsif ( $months !~ $month ) {
            $voltsum = 0;
            $wattsum = 0;

}
}

}
close (DATAFILE);



#               print "Month  Year Watts     Vars\n" ;
#               print "--------------------------\n";
#               print " $months $month    $year $wattsum $voltsum\n\n";

Ответы [ 3 ]

2 голосов
/ 17 января 2012

Вы можете воспользоваться модулем для анализа вашей метки времени. Тем не менее, простое исправление может сделать что-то вроде этого:

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

Не совсем водонепроницаемый, но он может удовлетворить ваши потребности. Затем вы можете просто извлечь данные за месяц с помощью

for my $month (keys %sum) {
    print "voltamp sum ($month): $sum{$month}{'voltamp'}\n";
    ....
}
1 голос
/ 17 января 2012

Следующая структура данных может быть более подходящей ( perldoc perldsc )

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'
                   }
        };
0 голосов
/ 17 января 2012

Если вы хотите сделать это потоковым - как выглядит ваша программа - при условии, что ваши данные отсортированы, вы должны сначала ввести переменную для проверки месяца, который состоит из месяца + года. Это безопаснее (апрель 2011 не апрель 2012).

  • Инициализировать «последний проверенный месяц»
  • Начальная сумма, где это необходимо, и сумма.
  • печать, когда пришло время печатать

Может выглядеть так:

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

Тем не менее, я бы также предпочел подвести итоги в хэше, как последние 2 ответа, которые возникли при написании этого, поэтому я пропускаю свое второе решение.

...