2013-03-10 82 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