如何从数据中选择最后一列并打印它的总和?

发布于 2025-01-09 02:55:29 字数 129 浏览 0 评论 0原文

尝试:

my @header = split(/\,/,$recIn,-1);
print "Header Feed Date: $header[2]\n";
chop($header[2]);

trying with:

my @header = split(/\,/,$recIn,-1);
print "Header Feed Date: $header[2]\n";
chop($header[2]);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

自在安然 2025-01-16 02:55:29
use warnings;
use strict;
use feature 'say';

my $tot = 0;

my $header = <>; 

while (<>) { 
    $tot += (split /,/)[-1];    
}

say join ',', 'FINAL', $.-1, $tot;

<> 运算符 读取以下行调用时在命令行提交的文件。 $.变量是最后使用的文件句柄的当前行号。

printf 可以很好地格式化数字(及其小数位数)。


上面处理来自文件的数据。但是,问题中显示的最后一行 FINAL... 确实是输入文件的最后一行,需要检查。那么也不应该对其进行处理,因此我们需要添加一个检查

while (<>) { 
    if (/^\s*FINAL/) { 
        my @fields = split /,/;
        if ($.-1 != $fields[1] or $tot != $fields[-1]) {
            warn "Wrong FINAL line: $_";
        }
        last;
    }

    $tot += (split /,/)[-1];    
}

,但是然后我们会多次(三)处理该行。首先将每一行分割到一个数组中并使用准备好的数组,这样更好,而且当然更适合检查输入数据。

while (<>) {
    my @fields = split /,/;

   # Is this the last line, with a summary to be checked?
    if ($fields[0] eq 'FINAL') {
        if ($.-1 != $fields[1] or $tot != $fields[-1]) {
            warn "Wrong FINAL line: $_";
        }
        last;
    }

    # Validate input if/as needed

    $tot += $fields[-1];
}

只有当文件太大,或者处理了很多这样的文件。但如果输入数据确实需要检查格式、有效性或以任何方式进行预处理,那么当然别无选择。 (在非常短的文件中,这可能更有效,但很难检测到这一点,因为它只有一行。)

如果文件不太大,另一种选择是首先将所有行读入数组,剥离去掉不需要的第一行(标题)和最后一个摘要行,并处理其余的

my @lines = <>;
chomp @lines;

my $header = shift @lines;

my $final = pop @lines;

foreach my $line (@lines) { 
    # or split into an array for checking of various fields etc
    $tot += (split /,/, $line)[-1];
}
say join ',', 'FINAL', scalar @lines, $tot;

CHECK_FINAL_LINE: { 
    my @fields = split /,/, $final;
    if ( $fields[1] != @lines or $fields[-1] != $tot ) { 
        warn "FINAL summary line wrong: $final";
    }
};

现在我们避免检查每一行是否是最后一行。

数据行数是数组@lines的长度,当在标量context,就像最后一个块中的 if 中一样。我将检查放在一个块中,以避免为程序的其余部分引入 @fields 数组(这样它的范围仅限于该块),并且我将该块命名为 CHECK_FINAL_LINE代码> 为了方便/清晰。块没有必要。

在打印计算出的最终值的行中,尽管我们有一个列表上下文,由 print 强加(因此由 say)强加,并且我们实际上需要一个显式的标量。

use warnings;
use strict;
use feature 'say';

my $tot = 0;

my $header = <>; 

while (<>) { 
    $tot += (split /,/)[-1];    
}

say join ',', 'FINAL', $.-1, $tot;

The <> operator reads lines of files submitted at command-line at invocation. The $. variable is the current line number of the last-used filehandle.

Formatting of numbers (and the number of their decimal places) is nicely down with printf.


The above processes data from a file. However, the last line, with FINAL..., that is shown in the question is indeed the last line of the input file, which need be checked. Then that also shouldn't be processed so we need to add a check

while (<>) { 
    if (/^\s*FINAL/) { 
        my @fields = split /,/;
        if ($.-1 != $fields[1] or $tot != $fields[-1]) {
            warn "Wrong FINAL line: $_";
        }
        last;
    }

    $tot += (split /,/)[-1];    
}

But then we process that line multiple (three) times. It is nicer, and also certainly more amenable to checking input data, to first split each line into an array and use the ready array

while (<>) {
    my @fields = split /,/;

   # Is this the last line, with a summary to be checked?
    if ($fields[0] eq 'FINAL') {
        if ($.-1 != $fields[1] or $tot != $fields[-1]) {
            warn "Wrong FINAL line: $_";
        }
        last;
    }

    # Validate input if/as needed

    $tot += $fields[-1];
}

This added array construction reflects visibly (and negatively) on the efficiency only if the file is rather large, or many such files are processed. But if input data indeed need be checked for format, validity, or pre-processed in any way, then of course there is no choice. (In very short files this may be more efficient but one would be hard pressed to detect that since it's about only one line.)

Another option, if the file isn't too large, is to read all lines into an array first, peel off the unneeded first line (header) and the last summary line, and process the rest

my @lines = <>;
chomp @lines;

my $header = shift @lines;

my $final = pop @lines;

foreach my $line (@lines) { 
    # or split into an array for checking of various fields etc
    $tot += (split /,/, $line)[-1];
}
say join ',', 'FINAL', scalar @lines, $tot;

CHECK_FINAL_LINE: { 
    my @fields = split /,/, $final;
    if ( $fields[1] != @lines or $fields[-1] != $tot ) { 
        warn "FINAL summary line wrong: $final";
    }
};

Now we avoid checking each and every line for whether it is the last.

The number of data lines is the length of the array @lines, produced when @lines array is used in scalar context, like in the if in the last block. I put the check in a block so to avoid introducing a @fields array for the rest of the program (this way it's scoped to that block only), and I name the block CHECK_FINAL_LINE for convenience/clarity. The block isn't necessary.

In the line where the calculated final is printed though we have a list context, imposed by print (and so by say), and we actually need an explicit scalar.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文