在 perl 中添加一个包含列总和的新列

在 perl 中添加一个包含列总和的新列

我有一个巨大的文本文件,其中包含以下几列

col1 col2 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
abc dec 10 20 30 40 50 60 70 80 90 11 12 13

我正在寻找的输出是新列 FullYear 中所有月份的添加。

col1 col2 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec FullYear
abc dec 10 20 30 40 50 60 70 80 90 11 12 13 486

我尝试使用 awk 命令,但是,我的数据具有巨大的精度。下面的命令给出了错误的输出。

awk -F ' ' {print $1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13" "$14" "$3+$4+$5+$6+$7+$8+$9+$10+$11+$12+$13+$14}' inputfile.txt > outputfile.txt

我需要编写一个 Perl 脚本来完成这项工作。

答案1

这在 Perl 中相当容易做到,即使是一行代码:

perl -MList::Util=sum -anE 'if (1 == $.) { say join(q{ }, @F, q{FullYear}) } else { say join(q{ }, @F, sum(@F[2..13])) }' «YOUR-FILE»

解释:

-MList::Util=sum加载 List::Util 模块并导入该sum函数。这与 相同use List::Util qw(sum)

-n告诉 Perl 逐行处理输入文件,为每一行运行脚本。 (实际上是多余的,因为下一个选项隐式地打开了它)。-a打开自动分割模式,因此我们得到一个@F每个字段有一个条目的数组。-E意味着我们将使用当前的 Perl 功能(在本例中为“say”)提供一个脚本作为命令行参数。

这些选项的完整详细信息可以在perlrun联机帮助页/podfile 中找到。

然后,这是脚本,添加了空格,并添加了注释解释:

if (1 == $.) {                        # $. is the line number. Line 1 is header line.
    say join(' ', @F, q{FullYear});   # print out the heder + FullYear
}
else {
    # print out rows + sum of columns 2..13. Remember Perl counts from 0 in arrays,
    # so column 2 is the 3rd column (the number for January).
    say join(' ', @F, sum(@F[2..13]));
}

顺便说一句:你可以要求 Perl 帮助理解单行代码(至少是你信任的——这对于不受信任的脚本来说是不安全的)-MO=Deparse,它会给出如下输出:

命令:

perl -MO=Deparse -MList::Util=sum -anE 'if (1 == $.) { say join(q{ }, @F, q{FullYear}) } else { say join(q{ }, @F, sum(@F[2..13])) }' t-file 

输出:

use List::Util (split(/,/, 'sum', 0));
use feature 'current_sub', 'bitwise', 'evalbytes', 'fc', 'postderef_qq', 'say', 'state', 'switch', 'unicode_strings', 'unicode_eval';
LINE: while (defined($_ = readline ARGV)) {
    our @F = split(' ', $_, 0);
    if (1 == $.) {
        say join(' ', @F, 'FullYear');
    }
    else {
        say join(' ', @F, &sum(@F[2..13]));
    }
}
-e syntax OK

因此,您可以看到List::Util负载、-n逐行运行以及-a添加split.

答案2

适合Math::BigFloat你的“巨大的精度”吗?

perl -MMath::BigFloat -ape 'my $s=0; $s += new Math::BigFloat($_) for @F[2..$#F]; s/$/ $s/'

abc dec 7.5 8.5
abc dec 7.5 8.5 16

您还可以List::Util::sumMath::BigFloat;一起使用但这毫无意义:

perl -MMath::BigFloat -MList::Util=sum -ape 's/$/" ".sum map new Math::BigFloat($_), @F[2..$#F]/e'

答案3

事实并非如此perl,但这似乎可以完成工作:

awk 'NR==1 {$(NF+1) = "FullYear"; print} NR>1 {subtotal=0; for(f=0;f<=NF; f++) {subtotal+=$f}; $(NF+1)=subtotal; printf( "%s %s %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f\n", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15 ) }' inputfile

答案4

只是@derobert 的一个变体:

perl -MList::Util=sum -nlE 'say "$_ ", sum((split)[2..13])||"FullYear"' input

或使用-a

perl -MList::Util=sum -nalE 'say "$_ ", sum(@F[2..13])||"FullYear"' input

相关内容