2010-01-06 82 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)