use strict; use warnings; use feature qw(say signatures); no warnings 'experimental::signatures'; use List::Util qw(sum); my (%cost, %month); while (<>) { chomp; s/^(\d{4}-\d{2})-\d{2}/$1/; # YYYY-MM-DD -> YYYY-MM my ($month, $category, undef, $cost) = split /\t/; $month{$month} = 1; $cost{$category} = {} unless $cost{$category}; &check_consistency($cost{$category}->{$month}, $cost, $month, $category); $cost{$category}->{$month} += $cost; } my @category = sort(keys %cost); my @month = sort(keys %month); say join("\t" => "Month", @category, "Out", "In", "Total"); for my $month (@month) { my @cost = map { $cost{$_}->{$month} // 0 } @category; my $out = sum(grep { $_ > 0 } @cost) // 0; my $in = sum(grep { $_ < 0 } @cost) // 0; my $total = sum(@cost) // 0; say join("\t" => $month, @cost, $out, $in, $total); } # 月毎にカテゴリーのコストの正負が一貫していることをチェックする sub check_consistency($sum, $cost, $month, $category) { !defined($sum) || $sum >= 0 == $cost >= 0 or die "$month の $category カテゴリーのコストの正負が一貫していません"; }