2010-01-06 107 views
2

我有兩個文件。第一個文件包含6個字符鍵(SA0001,SA1001等)的列表。第二個文件包含日期和金額列表,前六個位置將與第一個文件中的鍵相匹配。我想驗證第一個文件中的每個鍵在第二個文件中至少有一個匹配。可能有多於一個匹配是可以的,第二個文件中可能有記錄,第一個文件中沒有鍵也是可以的。所以基本上是一個循環內的循環。當我想在第一次匹配後跳出內部循環時會出現問題,因爲第二個文件可能相當大。它正確地打印出「找到」消息並且中斷,但是如果到達第二個文件的末尾而沒有找到匹配,它將不會打印「未找到」消息。我的代碼到目前爲止是:從文件中搜索字符串

unvalues = open("file1.txt", "r") 
newfunds = open("file2.txt", "r").readlines() 
i = 1 
for line in newfunds: 
    line = line.strip() 
    for line2 in iter(unvalues.readline, ""): 
     try: 
      if line == line2[:6]: 
       print "%s: Matching %s to %s for date %s" % (i, line, line2[:6], line2[6:14]) 
       break 
     except StopIteration: print "%s: No match for %s" % (i, line) 
    i += 1 
    unvalues.seek(0) 
+0

你考慮使用一個SQL數據庫? – 2010-01-06 20:34:44

+0

第二個文件每天都在變化。我想安排這個腳本,然後讓它只打印不匹配。用戶可以查看輸出並確定發生不匹配的原因。數據庫會增加開銷。 – 2010-01-06 20:43:28

+0

每個文件有多少行,大約? – 2010-01-06 20:49:31

回答

3

使用裝置來代替:

set1=set(line[:6] for line in open('file1.txt')) 
set2=set(line[:6] for line in open('file2.txt')) 
not_found = set1 - set2 
if not_found: 
    print "Some keys not found: " + ', '.join(not_found) 
+0

集合的大小是否有限制?也就是說,如果文本文件超過特定大小,腳本將會失敗? – 2010-01-06 20:49:04

+0

是的,有一個限制,但它是相當大的 - 例如,一百萬件物品不應該是一個問題。一個集合只存儲唯一值,因此您不需要爲文件中的每行添加一個條目:每個唯一鍵值只有一個條目。您的文件可能包含多少個唯一密鑰? – 2010-01-06 20:51:31

+0

我明白了。唯一鍵的數量不能超過256個。因爲每個鍵只能列出一次,所以File1不能超過該行數。 File2可能有成千上萬行,它也永遠不會超過256個唯一鍵。 – 2010-01-06 20:57:15

0

我不認爲休息;引發StopIteration。

您通常不希望使用異常來控制流量控制。

0

瀏覽每個文件一次,將每條記錄添加到值等於1的散列。然後確保第一個散列的鍵是第二個散列的鍵的子集。

hashes = [] 
for f in ["file1.txt","file2.txt"]: 
    lines = open(f,"r").readlines() 
    hash = {} 
    for line in lines: 
     hash[line[:6] = 1 
    hashes.append(hash) 

set_keys1 = set(hashes[0].keys()) 
set_keys2 = set(hashes[1].keys()) 
assert(set_keys1.issubset(set_keys2)) 
0

我想你想要的東西,這可能是更接近:

unvalues = dict((line[:6], line[6:14]) for line in open("file1.txt", "r")) 
newfunds = [line for line in open("file2.txt", "r")] 
for i, line in enumerate(newfunds): 
    key = line.strip() 
    if key in unvalues: 
     v = unvalues[key] 
     print "%s: Matching %s to %s for date %s" % (i+1, line, key, v) 
    else: 
     print "%s: No match for %s" % (i+1, line) 
2
first_file=open("file1.txt","r") 
#save all items from first file into a set 
first_file_items=set(line.strip() for line in first_file) 
second_file=open("file2.txt","r") 
for line in second_file: 
    if line[:6] in first_file_items: 
     #if this is item from the first file, remove it from the set 
     first_file_items.remove(line[:6]) 
     #when nothing is left in the set, we found everything 
     if not first_file_items: break 

if first_file_items: 
    print "Elements in first file but not in second", first_file_items 
+0

+1這是最好的答案......建議一點點解釋:改變'if len(first_file_items)== 0:'如果不是first_file_items:'並且改變if if(first_file_items):'to'if first_file_items :' – 2010-01-06 23:18:34

+0

我試圖讓初學者清楚,但你是對的。 – 2010-01-07 07:17:14

0

你不能夠(而且不是必須)捕捉StopIteration異常在迭代器完成時發生,因爲它會被for循環自動捕獲。要做你似乎想要做的事情,你可以在你的for block之後使用else塊,例如你可以用這個代替您的內部循環:當for循環完成且沒有break語句擊中執行

for line2 in iter(unvalues.readline, ""): 
    if line == line2[:6]: 
     print "%s: Matching %s to %s for date %s" % (i, line, line2[:6], line2[6:14]) 
     break 
else: 
    print "%s: No match for %s" % (i, line) 

else塊。

但是,您可能會發現使用套件的其他方法之一更快。

0
from collections import defaultdict 

unvalues = open("file1.txt", "r").readlines() 
newfunds = open("file2.txt", "r").readlines() 

unvals = defaultdict(int) 

for val in unvalues: 
    unvals[val] = 0 

for line in newfunds: 
    line = line.strip() 

    if line[:6] in unvals.keys(): 
     unvals[line[:6]] += 1 

for k in unvals.keys(): 
    if unvals[k] == 0: 
     print "Match Not Found For %s" % k 

可能會給你一個很好的起點,你想達到什麼,而不是雜亂無章。這爲您提供了單獨循環每個數據集的性能優勢。

作爲快速增編,如果你想要行號,而不是建立一個計數變量外循環,並增加它,試試這個:

for i, line in enumerate(newfunds): 

枚舉()基本上拉鍊連續整數迭代器與列表以產生期望的結果而無需不必要的計數操作。

0

使用另一種方法套

keys = set(line[:6] for line in open('file.txt')) 
missing = set(value[:6] for value in open('file2.txt') if value[:6] not in keys) 
if missing: 
    print "Keys Missing " + ', '.join(missing)