Поиск файла для строк из второго файла - PullRequest
2 голосов
/ 06 января 2010

У меня есть два файла. Первый файл содержит список из 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)

Ответы [ 8 ]

3 голосов
/ 06 января 2010

Вместо этого используйте наборы:

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)
2 голосов
/ 06 января 2010
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 голосов
/ 07 января 2010

Другой подход с использованием наборов

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)
0 голосов
/ 07 января 2010
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):

enumerate () в основном архивирует последовательный целочисленный итератор с вашим списком, чтобы получить желаемый результат без лишних операций подсчета.

0 голосов
/ 06 января 2010

Вы не можете (и не должны) перехватывать исключение StopIteration, возникающее после завершения итератора, потому что оно автоматически перехватывается циклом for. Чтобы сделать то, что вы пытаетесь сделать, вы можете использовать блок else после блока for, например, Вы можете заменить свой внутренний цикл следующим образом:

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 выполняется по завершении цикла for без попадания оператора break.

Однако, вы можете обнаружить, что один из других подходов с использованием наборов быстрее.

0 голосов
/ 06 января 2010

Я думаю, это может быть ближе к тому, что вы хотите:

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)
0 голосов
/ 06 января 2010

Просмотрите каждый файл один раз, добавив каждую запись в хеш со значением, равным 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 голосов
/ 06 января 2010

Я не думаю, что перерыв; бросает стоп-изменение.

Как правило, вы не хотите использовать исключения для управления потоком данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...