Arrays 在Perl中为每个ID在数组中添加所有值
我有这张桌子:Arrays 在Perl中为每个ID在数组中添加所有值,arrays,perl,hash,sum,shift,Arrays,Perl,Hash,Sum,Shift,我有这张桌子: NAME | 12/31/2016 |值 AAA | 1/31/2017 | 10 AAA | 2/1/2017 | 20 AAA | 2/2/2017 | 30 AAA | 2/3/2017 | 40 AAA | 2/4/2017 | 50 名称| 2/9/2017 |价值 BBB | 2/10/2017 | 20 BBB | 2/11/2017 | 30 BBB | 2/12/2017 | 40 BBB | 2/13/2017 | 50 BBB | 2/14/2017 | 6
NAME | 12/31/2016 |值
AAA | 1/31/2017 | 10
AAA | 2/1/2017 | 20
AAA | 2/2/2017 | 30
AAA | 2/3/2017 | 40
AAA | 2/4/2017 | 50
名称| 2/9/2017 |价值
BBB | 2/10/2017 | 20
BBB | 2/11/2017 | 30
BBB | 2/12/2017 | 40
BBB | 2/13/2017 | 50
BBB | 2/14/2017 | 60
这就是我想要的结果:
NAME | DATE | VALUE
AAA | 12/31/2016 | 150
AAA | 1/31/2017 | 140
AAA | 2/1/2017 | 120
名称|日期|值
BBB | 2/9/2017 | 200
BBB | 2/10/2017 | 180
BBB | 2/11/2017 | 150
我想做的是,对于每个有效符号,(AAA
,BBB
)我想有三行
对于每列的第一行,我希望添加所有值
例如,AAA的第1行值:
10+20+30+40+50=150
对于第2行,我只想将第二个值添加到最后一个值
例如,AAA的第2行值
20+30+40+50=140
同样的情况也适用于BBB
我想将日期向下移动,以便12/31/2016
与AAA
匹配,然后获得每行的前三个日期
我现在有这个代码。但这没什么用。它只是给了我一堆数字
使用严格;
使用警告;
使用Scalar::Util qw(看起来像数字);
使用数据::转储程序;
附属大学{
我看到的百分比;
grep!$seen{$}++,@;
}
我的%现金流;
我的%fields=(
ID=>0,
日期=>1,
值=>2,
);
我的@total;
我的@IDs;
我的@uniqueid;
我的日期;
我的@add;
我的$i=0;
我的价值观;
我的$counter=3;
打开(文件“try.CSV”);
while(我的$line=){
chomp($line);
my@lineVals=拆分(/\\\\/,$line);
if($lineVals[$fields{ID}]!~/^SYMBOL$/i){
推送@IDs,$lineVals[$fields{ID}];
}
@uniqueIDs=uniq(@IDs);
#将所有现金流金额推送到@cashflow
if(看起来像数字($lineVals[$fields{VALUE}])){
$lineVals[$fields{VALUE}]=~s/\r/;
push@total,$lineVals[$fields{VALUE}];
}
如果($lineVals[$fields{DATES}]=~/(\d{1,2})\/(\d{1,2})\/(\d{4})/){
$lineVals[$fields{DATES}]=sprintf('%04d%02d%02d',$3,$2,$1);
}
$cashflow{uc$lineVals[$fields{ID}]}{DATES}=$lineVals[$fields{DATES}];
$cashflow{uc$lineVals[$fields{ID}]}{VALUE}=$lineVals[$fields{VALUE}];
foreach my$ID(@uniqueIDs){
foreach my$symb(钥匙%现金流){
如果($ID=$symb){
if(看起来像数字($lineVals[$fields{VALUE}])){
$lineVals[$fields{VALUE}]=~s/\r/;
push@total,$lineVals[$fields{VALUE}];
我的$i=0;
我的$grand=0;
foreach my$val(@total){
而($i<$counter){
$grand+=$val;
打印“$grand\n”;
$i++;
}
移位@总数;
}
}
}
}
}
}
关闭文件;
我真的被这件事缠住了。我不知道该怎么处理这个问题。一个可能的解决方案:
#!perl
use strict;
use warnings;
sub trim {
my ($str) = @_;
s!\A\s+!!, s!\s+\z!! for $str;
$str
}
my $file = 'try.CSV';
open my $fh, '<', $file or die "$0: $file: $!\n";
my ($group_name, @dates, @values);
my $sum = 0;
my $print_group = sub {
return if !defined $group_name;
my $format = " %-6s|%-11s|%s\n";
printf $format, 'NAME', 'DATE', 'VALUE';
for my $date (@dates) {
printf $format, $group_name, $date, $sum;
$sum -= shift @values if @values;
}
};
while (my $line = readline $fh) {
my ($name, $date, $value) = map trim($_), split /\|/, $line;
if ($name eq 'NAME') {
$print_group->();
$group_name = undef;
@dates = $date;
@values = ();
$sum = 0;
next;
}
$group_name ||= $name;
push @dates, $date if @dates < 3;
push @values, $value if @values < 2;
$sum += $value;
}
$print_group->();
用于从字符串中删除前导/尾随空格的辅助函数。我们正在使用
作为此处的s
分隔符,因为/
打破了SO的语法突出显示。耸耸肩
my $file = 'try.CSV';
open my $fh, '<', $file or die "$0: $file: $!\n";
我们设置了一些要在循环迭代中保留的状态变量$group\u name
是我们当前正在处理的组的名称,@dates
是我们到目前为止看到的保存日期,@values
是我们到目前为止看到的保存值$sum
是当前组中所有值的运行总和,它从0
开始
my $print_group = sub {
return if !defined $group_name;
my $format = " %-6s|%-11s|%s\n";
printf $format, 'NAME', 'DATE', 'VALUE';
for my $date (@dates) {
printf $format, $group_name, $date, $sum;
$sum -= shift @values if @values;
}
};
用于打印单个组的输出的辅助函数。如果未设置$group\u name
,则我们尚未处理当前组的任何输入,因此不执行任何操作并返回。否则,我们将打印一个NAME | DATE |值
标题,后面是@dates
中每个元素的一行数据。对于每个$date
,我们输出当前组名(例如AAA
)、$date
,以及值的总和(所有值都使用printf
进行了良好的格式化)。最初,$sum
是所有组值的总和,但在第一次迭代后,我们开始从@值中减去值:如果输入中的值列表是x1
,x2
,x3
,x4
,…,则$sum
最初是x1+x2+x3+x4+…
,这就是第一行输出的内容。然后我们减去x1
,因此下一行得到x1+x2+x3+x4+…-x1
,即x2+x3+x4+…
。然后我们减去x2,第三行数据得到x3+x4+…
while (my $line = readline $fh) {
my ($name, $date, $value) = map trim($_), split /\|/, $line;
我们的主回路。我们读取一行输入,在|
上拆分它,然后修剪每个字段
if ($name eq 'NAME') {
$print_group->();
$group_name = undef;
@dates = $date;
@values = ();
$sum = 0;
next;
}
如果$name
是'name'
,则这是新组的开始。如果有,打印当前组的输出($Print\u group->()
如果没有当前组,则不执行任何操作),然后将状态变量重置回初始值,除了@dates
,该值由标题行中的$date
值填充。然后开始循环的下一次迭代,因为我们已经完成了这一行
$group_name ||= $name;
push @dates, $date if @dates < 3;
push @values, $value if @values < 2;
$sum += $value;
在循环结束时,我们刚刚处理完一个组,因此我们也需要在此处调用$print\u group
。一个可能的解决方案:
#!perl
use strict;
use warnings;
sub trim {
my ($str) = @_;
s!\A\s+!!, s!\s+\z!! for $str;
$str
}
my $file = 'try.CSV';
open my $fh, '<', $file or die "$0: $file: $!\n";
my ($group_name, @dates, @values);
my $sum = 0;
my $print_group = sub {
return if !defined $group_name;
my $format = " %-6s|%-11s|%s\n";
printf $format, 'NAME', 'DATE', 'VALUE';
for my $date (@dates) {
printf $format, $group_name, $date, $sum;
$sum -= shift @values if @values;
}
};
while (my $line = readline $fh) {
my ($name, $date, $value) = map trim($_), split /\|/, $line;
if ($name eq 'NAME') {
$print_group->();
$group_name = undef;
@dates = $date;
@values = ();
$sum = 0;
next;
}
$group_name ||= $name;
push @dates, $date if @dates < 3;
push @values, $value if @values < 2;
$sum += $value;
}
$print_group->();
用于从字符串中删除前导/尾随空格的辅助函数。我们正在使用
作为此处的s
分隔符,因为/
打破了SO的语法突出显示。耸耸肩
my $file = 'try.CSV';
open my $fh, '<', $file or die "$0: $file: $!\n";
我们设置了一些要在循环迭代中保留的状态变量。
}
$print_group->();