[英]Sum hash elements with Perl
我有一个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;
}
首先,您的数据结构令人困惑。 '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'} || 0
如果其中一个哈希没有'IN1'
,则将使用零。 这基本上是对定义的哈希键的检查。 ||
对于哈希键,可以这样做。 但是,在其他情况下,则需要使用define-or运算符( //
,我相信可以从5.10版获得)。
$_->{'In1Total'} = $total+=$_->{'IN1'} || 0
$_->{'In1Total'} = $total+=$_->{'IN1'} || 0
这会将IN1
的当前值添加到计数中,然后将结果放入In1Total
。 诚然,可以通过将其分成几行来使其更加清晰。
更新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,
},
],
}
没有看到您的代码,很难知道为什么它不起作用,但这可能是因为您在代码中使用了哈希,但是返回的数据结构是哈希引用。
这是一个应该工作的版本(使用哈希引用):
#!/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
}
]
};
也许您可以从修改代码中学到一些东西,顺便说一句,它工作得很好。 问题是您对待数据结构错误。 这个:
# 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
}
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.