2011-10-06 56 views
0

我有兩個文件正在讀取,我在兩個文件中都找到了一些行。我需要編寫一個函數來檢測這兩個文件中的哪些行。現在我爲此寫了代碼,它將讀取文件1的內容並將記錄放入一個數組列表中,然後讀取文件2,對於file2中的每一行,我檢查它是否在數組列表中找到,如果發現它,我知道它是重複的行。現在我的問題是我在節省了整行列表中的所有行,我想知道是否有可能將我讀的行轉換爲散列碼,然後我將這個散列碼保存到數組列表中,之後,我會將這個散列碼與我正在從file2讀取的行的哈希碼,這是更好的方法來節省內存嗎?使用哈希碼來比較java中的兩個大字符串?

+3

兩個完全不同的字符串*可以*具有相同的哈希碼。它不是**可以確保無限數量的可能字符序列在「int」值中的唯一性。 – BalusC

+0

看看這可能幫助http://code.google.com/p/google-diff-match-patch/ –

+0

擔心內存在這一點聽起來像一個不成熟的優化而不是幫助這可能花費更多。 – bzlm

回答

2

您正在查找HashSet<String> - 它完全符合您的需求!


實施例:

Set<String> file1  = ....// read line by line from file1 
ArrayList<String> file2 = ... //  -  "  -  file2 

for (String line : file1) 
    if (file2.contains(line)) 
     duplicate found 
5

如果這兩個散列碼是不同的,這些線是不同的。如果兩個哈希碼相同,那麼這些行可能會相同,也可能不相同。

如果將文件存儲在HashSet中,則查找一行是否已存在是非常快速的操作。 HashSet在內部使用哈希碼。

+0

它如果速度很快,但沒有解決問題所提及的內存問題。 –

+0

+1表示明確的答案,並且還提供了「HashSet」建議。 – Qwerky

3

這是一種可以節省內存,但不能保證匹配的方法。哈希碼的定義表示它們不會是唯一的。如果你想存儲一個較小版本的字符串,那麼你應該存儲一個像MD5這樣的字符串摘要。

下面是你如何得到摘要。

import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
... 
MessageDigest md = MessageDigest.getInstance("MD5"); 
byte[] digestBytes = md.digest(string.getBytes()); 

MD5是16個字節長,所以如果你的字符串顯著超過8個字符(每個字符2個字節),這隻會爲你節省內存。

但是,除非您的文件非常大,否則您確實不需要擔心內存,HashSet答案會給您更好的結果。

編輯:

MD5不發出碰撞而不是在現實世界中的條件。它不應該用作密碼哈希碼,但在這種情況下可以正常工作。還有其他的摘要函數,例如SHA256,其碰撞機率較小,但摘要尺寸較大。

+0

MD5仍然是一個散列函數,並且仍然存在衝突。 –

+0

MD5 *是*的密碼哈希碼,但它是更摘要算法相比'INT的hashCode()'。它確實發射了碰撞,但不是在現實世界的條件下。唯一的碰撞是在實驗室中設計的。 – Gray

0

如果你實在擔心內存,並且願意在以安全存儲性能較差,你可以做到以下幾點:

  1. 文件1.
  2. 創建哈希值的HashSet的創建文件2中與文件1的散列值相匹配的散列值的HashSet。
  3. 從散列值位於HashSet 2中的文件1創建行的HashSet。
  4. 檢查文件2中的每一行對HashSet 3.
0

你沒有提到文件的大小限制,所以我假設它們可能足夠大,以至於無法將所有行存儲在內存中。

所以,我建議以下方法:

  1. 將兩者連接起來的文件創建一個大文件。

  2. 使用「外部」排序算法,例如,http://code.google.com/p/externalsortinginjava/到大文件進行排序。

  3. 讀取排序後的文件,每次只讀一行,並將每行與之前的行進行比較(只保留內存中的兩行 - 當前行和前一行)。如果當前行和前一行是相同的,則該行將出現在兩個原始文件中。

「外部排序」是經常計算早些日子在必要的時候要少得多的內存可用。這樣做是的單程/是歸併排序,這是與磁帶(磁帶記得?),被稱爲「帶一種」使用時。是的,我老了:-)

+0

連接兩個文件使得無法區分這兩個文件。另一種方法是對兩個文件進行排序,並不斷比較file1中的一行和file2中的一行。 – Sjoerd

+0

我沒有看到原始問題中需要區分兩個文件中的行的任何內容。我們所需要知道的是,如果兩條線都出現同一條線。因此,如果在排序後重復一行,則它在兩個文件中(假設它不能在同一個文件中出現兩次)。 – GreyBeardedGeek

0

如果您擔心空間/內存問題,請將字符串轉換爲base36,然後再按照多位用戶的建議將它們存儲在HashSet中。爲了使事物標準化,我建議在創建base36等價物之前,從字符串中去除所有空白和標點符號並將其轉換爲小寫字母。然後在HashSet你結束了HashSet<String>其中字符串包含字符串而不是整個字符串的base36編碼。