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

列中重复值处理问题:Perl脚本重复输出结果求助

解决Perl脚本重复输出的问题

我来帮你排查这个脚本的问题,顺便给你修正方案~

你的问题背景

原始数据

你有一个包含交易记录的文件,格式如下:

02-May-2018,AAPL,Sell,0.25,1000
02-May-2018,C,Sell,0.25,2000
02-May-2018,JPM,Sell,0.25,3000
02-May-2018,WFC,Sell,0.25,5000
02-May-2018,AAPL,Sell,0.25,7000
02-May-2018,GOOG,Sell,0.25,8000
02-May-2018,GOOG,Sell,0.25,9000
02-May-2018,C,Sell,0.25,2000
02-May-2018,AAPL,Sell,0.25,3000

需求

当第二列的股票代码出现次数超过2次时,输出该代码对应的所有原始行。比如AAPL出现了3次,需要输出它的全部3条记录。

有问题的脚本

你写的脚本会重复输出结果,不符合预期:

open (FILE, "<$TMPFILE") or die "Could not open $TMPFILE";
open (OUT, ">$TMPFILE1") or die "Could not open $TMPFILE1";
%count = ();
@symbol = ();
while ($line = <FILE>) {
    chomp $line;
    (@data) = split(/,/,$line);
    $count{$data[1]}++;
    @keys = sort {$count{$a} cmp $count{$b}} keys %count;
    for my $key (@keys) {
        if ( $count{$key} > 2 ) {
            print "$line\n";
        }
    }
}

问题根源

你的脚本逻辑顺序错了:

  • 你每读一行就立刻更新计数,然后遍历所有已统计的股票代码——只要有任何一个代码计数超过2,就打印当前行。这会导致同一行被多次输出(比如当多个代码计数都达标时,当前行被打印多遍)。
  • 而且你是边读行边判断,此时计数还没统计完。比如读到第三行AAPL时,计数刚到3,这时候会打印第三行,但前面的两行AAPL根本没被输出,因为之前它们的计数还没到3。

简单说,你的逻辑是读一行就检查所有计数,符合条件就打当前行,这既会重复打印,也会漏掉前面符合条件的行。

修正后的脚本

正确的思路应该是先统计所有股票的出现次数,再重新读取文件输出符合条件的行,这样能保证只输出正确的行,且不重复。

方案一:两次读取文件(适合大文件,内存占用低)

use strict;
use warnings; # 这两行是Perl编程的好习惯,能帮你提前发现潜在错误

my $TMPFILE = 'your_input_file.txt'; # 替换成你的实际输入文件名
my $TMPFILE1 = 'output.txt'; # 替换成你的实际输出文件名

# 第一步:遍历文件,统计每个股票代码的出现次数
my %count;
open(my $in_fh, '<', $TMPFILE) or die "Could not open $TMPFILE: $!";
while (my $line = <$in_fh>) {
    chomp $line;
    my @data = split(/,/, $line);
    $count{$data[1]}++;
}
close $in_fh;

# 第二步:再次遍历文件,输出符合条件的行
open(my $out_fh, '>', $TMPFILE1) or die "Could not open $TMPFILE1: $!";
open($in_fh, '<', $TMPFILE) or die "Could not open $TMPFILE again: $!";
while (my $line = <$in_fh>) {
    chomp $line;
    my @data = split(/,/, $line);
    if ($count{$data[1]} > 2) {
        print $out_fh "$line\n"; # 输出到指定文件,而不是控制台
    }
}
close $in_fh;
close $out_fh;

方案二:一次读取所有行到内存(适合小文件,代码更简洁)

如果你的文件不大,可以先把所有行存到数组里,再统计计数,最后遍历数组输出:

use strict;
use warnings;

my $TMPFILE = 'your_input_file.txt';
my $TMPFILE1 = 'output.txt';

my @all_lines;
my %count;

# 读取所有行到数组,同时统计计数
open(my $in_fh, '<', $TMPFILE) or die "Could not open $TMPFILE: $!";
while (my $line = <$in_fh>) {
    chomp $line;
    push @all_lines, $line;
    my @data = split(/,/, $line);
    $count{$data[1]}++;
}
close $in_fh;

# 输出符合条件的行
open(my $out_fh, '>', $TMPFILE1) or die "Could not open $TMPFILE1: $!";
foreach my $line (@all_lines) {
    my @data = split(/,/, $line);
    if ($count{$data[1]} > 2) {
        print $out_fh "$line\n";
    }
}
close $out_fh;

额外优化说明

  • 用use strict;和use warnings;能帮你捕获变量未声明、类型错误等问题,避免很多隐性bug。
  • 使用词法文件句柄($in_fh、$out_fh)代替旧式的FILE、OUT,更安全且符合现代Perl规范。
  • 在die语句中加上$!,能输出具体的系统错误原因,方便调试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:53:14