2013-03-10 54 views
0

我有一个输入文件,存在这么多的冗余记录,我试图写一个程序来删除冗余的一部分,但它似乎仍然有一些冗余,但我找不到什么地方错了不能摆脱相同的记录

ARGV [0]是与冗余输入文件

ARGV [1]是没有输入文件的冗余输出文件

open(Input,"<./$ARGV[0]"); 
open(Output,">./$ARGV[1]"); 

while(eof(Input) !=1) 
{ 
    push(@Records,readline(*Input)); 
} 
close Input; 

# Solution 2 
for($i=0;$i<$#Records;$i++) 
{ 
    for($j=$i+1;$j<$#Records;$j++) 
    { 
     if($Records[$i] eq $Records[$j]) 
     { 
      $Records[$j] = undef; 
     } 
    } 
} 

@Records = grep defined,@Records; 

=begin 
# Solution 1 have some problems 
for($i=0;$i<$#Records;$i++) 
{ 
    for($j=$i+1;$j<$#Records;$j++) 
    { 
     if($Records[$i] eq $Records[$j]) 
     { 
      splice @Records,$j,1; 
      $j = $j-1; 
     } 
    } 
} 
=end 
=cut 

foreach $Each(@Records) 
{ 
    print Output $Each; 
} 
close Output; 

感谢

回答

1

你的“解决方案1”是最接近的。将数组元素设置为undef不会将其删除,并且如果您应该已启用警告,则会引发警告消息。

该溶液在索引$j检查每个记录和会删除使用splice它,如果它是一个重复的(其将洗牌剩余记录下来,使得下一记录进行比较将在同一索引)或叶它到位并通过递增$j跳过它。

最好使用词法文件句柄(如$infh)而不是裸文件句柄(如Input)。您还应该使用open的三参数表格和总是检查它是否成功。这里我使用了autodie来避免明确地检查每个open。如果任何open调用失败,它将抛出异常。

use strict; 
use warnings; 
use autodie; 

my ($infile, $outfile) = @ARGV; 

my @records = do { 
    open my $infh, '<', $infile; 
    <$infh>; 
}; 

for my $i (0..$#records-1) { 
    my $j = $i + 1; 
    while ($j < @records) { 
     if ($records[$j] eq $records[$i]) { 
      splice @records, $j, 1; 
     } 
     else { 
      ++$j; 
     } 
    } 
} 

open my $outfh, '>', $outfile; 
print $outfh $_ for @records; 
close $outfh; 

使用哈希另一种解决方案是这样的

use strict; 
use warnings; 
use autodie; 

my ($infile, $outfile) = @ARGV; 

open my $infh, '<', $infile; 
open my $outfh, '>', $outfile; 

my %seen; 

while (<$infh>) { 
    print $outfh $_ unless $seen{$_}++; 
} 
+0

不要忘记关闭文件句柄 – 2013-03-10 13:26:10

+0

词法文件句柄在超出范围时会自动关闭,所以通常不需要明确关闭它们。 – 2013-03-10 16:16:38

1

您可以简单地使用uniq()

my @records; 
while(eof(Input) !=1) 
{ 
    push(@records,readline(*Input)); 
} 
close Input; 

@records = uniq(@records); ## Unique elements in @records 

请看看它的文档here

+1

你真的应该说从哪里得到 – Borodin 2013-03-10 10:01:58

+0

'uniq'是的,很简单的方法,谢谢... – user2131116 2013-03-10 10:03:44

+0

@Borodin请更正我如果链接错误。 – 2013-03-10 10:04:50

2

这是一个比较perl的,现代化的解决方案:

open(my $fh_input, '<', $ARGV[0]) or die $!; 
open(my $fh_output, '>', $ARGV[1]) or die $!; 
my %records =(); 

while(my $line = <$fh_input>) 
{ 
    $records{$line} = 1; 
} 

foreach my $record(keys %records) 
{ 
    print $fh_output $record; 
} 

close $fh_input; 
close $fh_output; 

正如你所看到的,我使用一个散列来避免重复

+0

这将随机输入记录的顺序,这不太可能是想要的。 – Borodin 2013-03-10 10:41:54

+0

使用Tie :: IxHash;如果订单很重要 – 2013-03-10 10:46:20

+1

这是笨拙和不必要的。如果以前没有看到过,则从输入文件中读取每行时才打印每行。查看我的解决方案的更新。 – Borodin 2013-03-10 10:50:14