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'は配列への参照であり、その要素の一部は文字列(など'1238')であり、残りの要素はハッシュ参照です。

Perlを使用するとこれを回避できますが、データ構造の各レベルで1種類のデータのみを保持する方が適切な設計になります。これは考慮すべきことです。ただし、とりあえずそのままにしておきます。

これを行う簡単な方法は次のとおりです。

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

use Data::Dumper;
print Dumper $VAR1;

更新: MikkoLが提案したように変更//されました。||

説明:

grep {ref $_}配列からハッシュ参照である要素のみを取得します。

$_->{'IN1'} || 0-ハッシュの1つにがなかった場合'IN1'、代わりにゼロが使用されます。これは基本的に、定義されているハッシュキーのチェックです。 ||ハッシュキーに対してこれを行うことは許容されます。ただし、他の状況では、defined-or演算子が必要です(//バージョン5.10から利用可能だと思います)。

$_->{'In1Total'} = $total+=$_->{'IN1'} || 0これにより、の現在の値がカウントに追加IN1され、結果がに入れられIn1Totalます。確かに、これは2、3行に分けることで、もう少し明確にすることができます。

更新2:ボロディンが指摘した間違いを修正。

于 2012-11-22T12:25:41.947 に答える
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 に答える
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 に答える