2

我有一个返回此哈希结构的 Perl 脚本:

$VAR1 = {
          'Week' => [
                      '1238',
                      {
                        'OUT3FA_5' => 65,
                        'OUT3A_5' => 20,
                        'OUT3-Fix' => 45,
                        'IN1' => 85
                      },
                      '1226',
                      {
                        'OUT3FA_5' => 30,
                        'OUT3A_5' => 5,
                        'OUT3-Fix' => 25,
                        'IN1' => 40
                      }
                    ]
        };

我想做的是,计算IN1每周的总数,每个例子在这种情况下它会返回:

$VAR1 = {
          'Week' => [
                      '1238',
                      {
                        'OUT3FA_5' => 65,
                        'Total_IN1' => 85,
                        'OUT3A_5' => 20,
                        'OUT3-Fix' => 45,
                        'IN1' => 85
                      },
                      '1226',
                      {
                        'OUT3FA_5' => 30,
                        'Total_IN1' => 125,
                        'OUT3A_5' => 5,
                        'OUT3-Fix' => 25,
                        'IN1' => 40
                      }
                    ]
        };

以此类推,每周一次。

请问我该怎么做?任何帮助,将不胜感激。

这是我试图做的,但它不起作用:

my @sum_IN1 = qw(IN1); #kinda useless to use an array just for one value...
for my $num (keys %hash) {

    my $found;
    my $sum = 0;

    for my $key (@sum_IN1) {

        next unless exists $hash{$num}{$key};
        $sum   += $hash{$num}{$key};
        $found = 1;
    }

    $hash{$num}{Total_IN1} = $sum if $found;
} 
4

4 回答 4

2

您需要保留一个状态变量来保存数组中每个项目的运行总计。我还怀疑你Week的数组应该是一个哈希?

use strict;
use warnings;

use Data::Dump;

my $data = {
  Week => [
    1238,
    { "IN1" => 85, "OUT3-Fix" => 45, "OUT3A_5" => 20, "OUT3FA_5" => 65 },
    1226,
    { "IN1" => 40, "OUT3-Fix" => 25, "OUT3A_5" => 5, "OUT3FA_5" => 30 },
  ],
};

my $week = $data->{Week};

# Sort the array entry pairs by week number
#
my @pairs;
push @pairs, [ splice @$week, 0, 2 ] while @$week;
@$week = ();
for my $pair (sort { $a->[0] <=> $b->[0] } @pairs) {
  push @$week, @$pair;
}

# Calculate the running totals of IN1
#
my $total = 0;
for my $item (@$week) {
  next unless ref $item eq 'HASH' and exists $item->{IN1};
  $total += $item->{IN1};
  $item->{Total_IN1} = $total;
}

dd $data;

输出

{
  Week => [
    1226,
    {
      "IN1"       => 40,
      "OUT3-Fix"  => 25,
      "OUT3A_5"   => 5,
      "OUT3FA_5"  => 30,
      "Total_IN1" => 40,
    },
    1238,
    {
      "IN1"       => 85,
      "OUT3-Fix"  => 45,
      "OUT3A_5"   => 20,
      "OUT3FA_5"  => 65,
      "Total_IN1" => 125,
    },
  ],
}
于 2012-11-22T13:59:28.057 回答
2

首先,您的数据结构令人困惑。'Week'是对数组的引用,其中一些元素是字符串(例如'1238'),其余元素是哈希引用。

虽然 Perl 可以让您侥幸逃脱,但最好将数据结构的每一层设计为只保存一种东西。这是需要考虑的事情。但是,我将暂时保留它。

这是一个快速的方法:

my $ttl = 0;
$_->{'In1Total'} = $ttl+=$_->{'IN1'} || 0 for(grep {ref $_} @{$VAR1->{'Week'}});

use Data::Dumper;
print Dumper $VAR1;

更新:更改//||Mikko L 建议的那样。

解释:

grep {ref $_}仅从数组中获取作为哈希引用的元素。

$_->{'IN1'} || 0- 如果其中一个哈希没有'IN1',这将使用零代替。这基本上是对正在定义的哈希键的检查。 ||对哈希键执行此操作是可以接受的。但是,在其他情况下,您需要定义或运算符 ( //,我相信从版本 5.10 可用)。

$_->{'In1Total'} = $total+=$_->{'IN1'} || 0这会将 的当前值添加IN1到计数中,然后将结果放入In1Total. 诚然,这可以通过将其分成几行来更清楚地说明。

更新 2:修正了 Borodin 指出的错误。

于 2012-11-22T12:25:41.947 回答
0

没有看到您的代码,很难看出它为什么不起作用,但这可能是因为您在代码中使用了哈希,但返回的数据结构是哈希引用。

这是一个应该工作的版本(使用哈希引用):

#!/usr/bin/env perl

use warnings;
use strict;
use Data::Dumper;
use List::MoreUtils qw( natatime );

my $data = {
    'Week' => [
        '1238',
        {   'IN1'      => 85,
            'OUT3FA_5' => 65,
            'OUT3A_5'  => 20,
            'OUT3-Fix' => 45
        },
        '1226',
        {   'IN1'      => 40,
            'OUT3FA_5' => 30,
            'OUT3A_5'  => 5,
            'OUT3-Fix' => 25
        }
    ]
};

for my $key ( keys %$data ) {
    my $weekly_data = $data->{$key};
    my $total       = 0;
    my $iter        = natatime 2, @$weekly_data;

    while ( my ( $id, $daily_data ) = $iter->() ) {
        next unless $daily_data->{IN1};
        $total += $daily_data->{IN1};
        $daily_data->{Total_IN1} = $total;
    }
}

print Dumper($data);
1;

这是输出:

$VAR1 = {
          'Week' => [
                      '1238',
                      {
                        'OUT3FA_5' => 65,
                        'Total_IN1' => 85,
                        'OUT3A_5' => 20,
                        'OUT3-Fix' => 45,
                        'IN1' => 85
                      },
                      '1226',
                      {
                        'OUT3FA_5' => 30,
                        'Total_IN1' => 125,
                        'OUT3A_5' => 5,
                        'OUT3-Fix' => 25,
                        'IN1' => 40
                      }
                    ]
        };
于 2012-11-22T11:26:27.447 回答
0

也许您可以从修改代码中学到一些东西,顺便说一句,它工作得很好。问题是您错误地对待数据结构。这个:

# initial data structure
my $data = {
    'Week' => [
        '1238',
        {
            'IN1' => 85,
            'OUT3FA_5' => 65,
            'OUT3A_5' => 20,
            'OUT3-Fix' => 45
        },
        '1226',
        {                        
            'IN1' => 40,
            'OUT3FA_5' => 30,                       
            'OUT3A_5' => 5,
            'OUT3-Fix' => 25
        },
    ],
};

是一个哈希引用。在引用的哈希中,有一个键Week指向键值对的数组引用。所以这应该是一个哈希:

# create a Week hash from the even-sized list in $data->{Week}
my %week = @{$data->{Week}};

我只需要替换代码中的一些变量名:

my @sum_IN1 = qw(IN1);
for my $num (keys %week) {

    my $found;
    my $sum = 0;

    for my $key (@sum_IN1) {

        next unless exists $week{$num}{$key};
        $sum   += $week{$num}{$key};
        $found = 1;
    }

    $week{$num}{Total_IN1} = $sum if $found;
}

print Dumper \%week;

这很好用!输出(顺序错误,但您可以sort轻松完成):

$VAR1 = {
          '1238' => {
                      'OUT3FA_5' => 65,
                      'Total_IN1' => 85,
                      'OUT3A_5' => 20,
                      'OUT3-Fix' => 45,
                      'IN1' => 85
                    },
          '1226' => {
                      'OUT3FA_5' => 30,
                      'Total_IN1' => 40,
                      'OUT3A_5' => 5,
                      'OUT3-Fix' => 25,
                      'IN1' => 40
                    }
        };
于 2012-11-22T11:38:17.580 回答