2016-08-02 57 views
0

我有2個(大)文件。第一個約20萬線,第二個約3千萬線。如何在Perl中匹配來自兩個大文件的數據?

我想檢查第一個的每一行是否在第二個使用Perl。 將第一行的每一行與第二行的每一行進行比較會更快嗎?還是更好地將它們全部存儲在兩個不同的數組中,然後操作數組?

+2

...還是有更好的方法,就像使用哈希? – mob

+0

就像在散列中存儲了3千萬行並檢查每條200k行是否在其中? – VeZoul

+0

好吧,我的情況有點特殊。事實上,我的文件是這樣的: 文件A:名稱編號(每行) 文件B:名稱日期位置編號(每行) 而且我必須檢查文件B是否包含與文件A的數據匹配的行(忽略日期和位置例如) 所以它不是一個完全匹配,必須先應用一個處理 – VeZoul

回答

1

將第一個文件的行存儲在散列中,然後迭代第二個文件而不將其存儲在內存中。

存儲第一個文件並迭代第二個文件可能會違反直覺,反之亦然,但它可以避免創建一個3000萬個元素的散列。

use feature 'say'; 

my ($path_1, $path_2) = @ARGV; 

open my $fh1,"<",$path_1; 
my %f1; 
$f1{$_} = $. while (<$fh1>); 

open my $fh2,"<",$path_2; 
while (<$fh2>) { 
    if (my $f1_line = $f1{$_}) { 
     say "file 1 line $f1_line appears in file 2 line $."; 
    } 
} 

注意,而無需進一步處理,重複的線將在它們出現在第二個文件,而不是第一順序顯示。

此外,假定文件1沒有重複的行,但可以根據需要進行處理。

+0

謝謝!我的第一個測試給了我45秒的執行時間。我現在必須改善我的搜索範圍,但我認爲這不會延長執行時間:) – VeZoul

7

你有文件和文件B.你要檢查,如果在文件中的線條出現在文件B.

如果你有足夠的內存使用每行一個條目的哈希持有文件B的內容,這是最簡單的。前進。

但是,如果您不這樣做,我建議您將兩個文件放在SQL數據庫的表中。 SQLite可能足以啓動。那麼,你的問題就簡化爲一個簡單的JOIN。如果行長度有問題,請使用快速散列,如xxHash。如果正確實施,64位版本在64位機器上快速發展,特別是如果您在Perl中啓用了優化。存儲兩列,散列和實際行。如果散列匹配,請檢查這些行是否匹配。確保在哈希列上進行索引。

你說:

事實上,我的文件是這樣的:文件:名稱數量(每行)文件B:(每行)名稱日期位置號碼,我要檢查,如果文件B包含與文件A的數據匹配的行(忽略日期和位置,例如)所以它不是完全匹配...

在這種情況下,您已設置。你甚至不必擔心哈希的東西(我將離開這裏作爲參考)。將需要匹配的數據的有趣部分放在SQLite數據庫的單獨列中。寫一個連接。利潤。

或者,您可以使用BerkeleyDB,它可讓您在將表存儲在磁盤上時具有內存散列的概念性簡單性。如果您有多個要匹配的屬性,則這不會很好地擴展。

+1

如果行數可能比SQL數據庫可用作索引的時間長,則這將不起作用。 –

+0

@MarkusLaire True。更新了我的答案。 –

+0

我必須在沒有連接到任何服務器或本地主機的計算機上運行程序。所以唯一的方法是內存存儲... – VeZoul

相關問題