You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl中List::Gather的gather构造多次调用失效问题求助

Perl中多次使用List::Gather提取数组元素失败问题排查

问题背景

处理自动气象站时间间隔数据时,每条记录包含8个站点的数据:前3个站点各13个字段,中间4个各35个字段,最后1个13个字段。使用List::Gather从同一数组提取字段时,第一次提取前13个字段正常,第二次提取第13至25个字段返回空结果。

数据样例

2024-08-02  00:00:00;15.0;50.6;2.9;7.6;38;29;-2.7;846.9;;28.0;0;93;12.7;14.4;47.6;3.8;8.0;86;101;-2.5;833.8;;30.6;0;56;12.9;12.9;60.7;3.2;6.7;45;56;-0.7;843.6;;82.2;0;76;12.8;14.0;53.2;2.2;3.7;50;41;-1.2;841.9;;19.2;0;63;12.9;10.0;8.8;8.5;7.5;7.7;7.2;8.1;8.3;8.8;8.4;9.3;9.7;1.9;4.2;5.7;4.5;5.8;7.4;7.1;7.1;14.1;7.9;23.7;26.3;12.7;61.0;1.9;4.2;22;51;-1.2;839.5;;45.2;0;66;12.9;8.4;7.9;7.6;6.8;6.8;7.2;7.2;7.5;7.6;8.3;8.6;8.7;2.2;16.3;13.2;9.0;28.0;22.4;27.2;34.3;41.0;39.4;47.4;48.3;13.5;50.4;2.6;5.0;44;60;-2.0;827.0;;29.6;1;53;13.0;10.0;9.3;8.7;7.8;7.0;7.3;7.6;8.2;8.3;9.3;9.8;10.0;0.2;5.8;11.4;17.7;23.5;22.3;18.5;11.4;5.5;9.5;20.9;19.6;14.2;51.3;1.7;5.2;40;20;-0.8;844.3;;42.4;0;57;12.9;8.3;8.3;8.7;7.9;7.8;8.2;9.7;9.8;9.9;10.4;10.5;10.4;0.3;10.9;3.6;2.7;0.8;15.6;33.9;33.5;33.4;37.6;36.8;35.2;12.4;52.9;;;;;-0.6;813.1;;0.0;0;46;13.0
2024-08-02 00:10:00;15.0;50.8;2.7;7.4;32;76;-0.8;847.1;;28.0;0;89;12.7;14.4;47.9;5.1;10.0;86;85;-1.4;833.8;;30.6;0;53;12.9;12.7;61.4;2.8;6.2;37;59;-1.3;843.5;;82.2;0;72;12.8;14.3;51.7;2.5;5.8;61;360;-0.5;841.6;;19.2;0;69;12.9;10.0;8.8;8.5;7.4;7.7;7.2;8.1;8.2;8.8;8.4;9.3;9.6;1.9;4.2;5.7;4.5;5.9;7.4;7.1;7.1;14.1;7.9;23.7;26.3;12.6;62.1;1.5;3.1;13;25;-0.9;839.5;;45.2;0;56;12.9;8.3;7.9;7.6;6.8;6.8;7.2;7.2;7.5;7.6;8.3;8.6;8.7;2.2;16.3;13.2;9.0;28.0;22.4;27.2;34.3;41.0;39.4;47.4;48.3;13.3;51.4;2.9;5.9;40;41;-1.3;827.0;;29.6;1;69;12.9;9.8;9.3;8.7;7.8;7.0;7.3;7.5;8.2;8.3;9.3;9.8;9.9;0.2;5.8;11.4;17.7;23.5;22.3;18.5;11.4;5.5;9.5;20.9;19.6;14.0;51.8;0.9;2.0;343;322;-0.7;844.3;;42.4;0;65;12.9;8.2;8.3;8.7;7.9;7.8;8.2;9.7;9.8;9.9;10.3;10.5;10.4;0.3;10.9;3.6;2.7;0.8;15.6;33.9;33.6;33.4;37.7;36.8;35.2;12.4;52.7;;;;;-0.8;812.8;;0.0;0;45;13.0
2024-08-02 00:20:00;15.0;51.6;2.3;6.2;46;65;-3.0;847.0;;28.0;0;103;12.7;13.9;49.1;4.4;7.5;79;89;-1.3;833.8;;30.6;0;54;12.9;12.7;62.7;3.1;6.3;45;6;-0.7;843.5;;82.2;0;69;12.8;14.4;50.6;2.9;5.7;25;14;-0.3;841.9;;19.2;0;56;12.9;10.0;8.8;8.5;7.5;7.7;7.2;8.1;8.3;8.8;8.4;9.2;9.7;1.9;4.2;5.7;4.5;5.9;7.4;7.1;7.1;14.1;7.9;23.7;26.3;12.4;63.1;2.0;4.3;28;49;-0.8;839.4;;45.2;0;64;12.9;8.3;7.9;7.6;6.8;6.8;7.2;7.2;7.5;7.6;8.3;8.6;8.7;2.2;16.3;13.2;9.0;28.0;22.4;27.2;34.3;41.0;39.4;47.4;48.3;13.5;51.4;4.1;6.9;32;42;-0.5;827.0;;29.6;0;69;12.9;9.8;9.3;8.7;7.8;7.0;7.3;7.5;8.2;8.3;9.2;9.8;10.0;0.2;5.7;11.4;17.7;23.5;22.3;18.5;11.4;5.5;9.5;20.9;19.6;13.8;55.6;2.2;5.1;303;317;-2.8;844.6;;42.4;0;71;12.9;8.3;8.3;8.7;7.9;7.8;8.2;9.7;9.8;9.9;10.4;10.5;10.4;0.3;10.9;3.6;2.7;0.8;15.6;33.9;33.5;33.4;37.7;36.8;35.2;12.1;53.6;;;;;-1.0;812.6;;0.0;0;57;12.9

原始代码

#!/usr/bin/perl -w
use strict;
use warnings;
use File::Path;
use File::Copy;
use Tie::File;
use List::Gather;
my @list_stns=("stn1","stn2","stn3","stn4","stn5","stn6","stn7","stn8");
my $list_stns;

my $datestr=qr{\d{4}-\d{2}-\d{2}};
my $timestr=qr{\d{2}:\d{2}:\d{2}};
my $file="data.csv";
my $nfile="newfile.txt";

my @array;
my $line; 
my $array;
my @array1;
my $array1;
my @first;
my @second;
my @third;

tie @array, 'Tie::File', $file, mode => O_RDWR;
my $x = shift @array;

for(@array){
s/;;;;;/;0.0;0.0;0.0;0.0;/g;
s/;;/;0.0;/g; 
s/;/ /g;
}

open (my $INFILE, "> ddata.csv") or die "open 'ddata.csv': failed $! ($^E)";
for (my$kk=0; $kk < @array; ++$kk){
 print $INFILE "$array[$kk]\n";
}
close($INFILE);

my $yr;
my $mn;
my $dy;
my $hr;
my $mi;

open (my $OUTFILE, "< ddata.csv") or die "open 'data.csv': failed $! ($^E)";
for (my $kk=0; $kk < @array; ++$kk){
 $array1[$kk]=<$OUTFILE>;
 $line=$array1[$kk];
my($datestr, $timestr, $all_fields)=split(' ', $line, 3);

$yr=substr($datestr, 0, 4);
$mn=substr($datestr, 5, 2);
$dy=substr($datestr, 8, 2);
$hr=substr($timestr, 0, 2);
$mi=substr($timestr, 3, 2);

my(@all_fields)=split(' ', $all_fields);
@first = gather{for(@all_fields){take $_ if gathered < 13}};
open (my $AWSF, "> $list_stns[0]") or die "open '$list_stns[0]': failed $! ($^E)";
print $AWSF "Year Mon Day Hr Mn Temp  Humd  Wspd  Wdir Press  Rain\n";

$_ = sprintf "%5.1f", $_ foreach @first;
print $AWSF "$list_stns[0]\n";
print $AWSF "$yr  $mn  $dy $hr $mi", join(" ", ($first[0],$first[1],$first[2],$first[4],$first[7],$first[8])),"\n";
close($AWSF);

@second = gather { for ( @all_fields) { take $_ if (gathered >= 13) && (gathered < 26)}};
print "@all_fields\n";
print "@second\n"; #this prints a blank line
exit;
open ($AWSF, "> $list_stns[1]") or die "open '$list_stns[1]': failed $! ($^E)";
print $AWSF "Year Mon Day Hr Mn Temp  Humd  Wspd  Wdir Press  Rain\n";

$_ = sprintf "%5.1f", $_ foreach @second;
print $AWSF "$list_stns[1]\n";
print $AWSF "$yr  $mn  $dy $hr $mi", join(" ", ($second[0],$second[1],$second[2],$second[4],$second[7],$second[8])),"\n";
close($AWSF);
}

问题原因

核心错误是对List::Gather中gathered函数的理解偏差:

  • gathered返回的是当前已收集到结果列表中的元素数量,而非遍历数组时的元素索引。
  • 第一次提取@first时,gathered <13逻辑成立:遍历数组时,每收集一个元素,gathered计数加1,直到收集满13个元素,符合预期。
  • 第二次提取@second时,(gathered >=13) && (gathered <26)逻辑完全错误:遍历数组时,初始gathered为0,前13个元素都不满足>=13的条件,不会被收集;后续元素遍历过程中,gathered始终保持0(没有元素被收集),最终结果为空数组。

解决方案

方案1:修正gather的使用逻辑(通过索引计数)

手动维护遍历的索引位置,根据索引筛选元素:

my $index = 0;
@second = gather {
    foreach my $elem (@all_fields) {
        take $elem if $index >=13 && $index <26;
        $index++;
    }
};

方案2:使用数组切片(更高效简洁)

不需要依赖List::Gather,Perl原生数组切片可以直接提取指定范围的元素:

@first = @all_fields[0..12];   # 前13个元素(索引0到12)
@second = @all_fields[13..25]; # 第13至25个元素(索引13到25)

额外代码优化建议

  1. 避免冗余文件IO:不需要用Tie::File修改原文件后写入ddata.csv,可以直接在内存中处理每行数据,减少磁盘操作。
  2. 文件追加模式:打开站点文件时使用>>追加模式,否则每次循环会覆盖之前的数据,最终仅保留最后一行记录。
  3. 移除无效代码:代码中的exit语句会终止程序,导致后续处理站点1的代码永远无法执行,需删除。

内容的提问来源于stack exchange,提问作者Zilore Mumba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 04:28:27