Я пытаюсь оптимизировать производительность скрипта Python, который ищет, содержится ли строка (имя класса) в файле. Файл содержит около 100 000 строк, каждая строка с именем класса.
def readFile(fileName):
fileObj = open(fileName, "r") # opens the file in read mode
words = []
lines = fileObj.read().splitlines()
# Using a for loop to check if word should be qualified as a class
# (Not included here for brevity)
for line in lines:
line = line.strip()
words.extend(line.split())
fileObj.close()
return words
#Actual array contains about 1000 classes to check
words[] = ["class1","class2","class3"]
# Contains about 100.000 lines
classes = readFile('classes.txt')
for word in words:
if (word in classes):
# do something
При запуске приведенного выше кода для завершения требуется около 60 секунд (включая некоторую конкатенацию строк, которая, я думаю, не должна быть узким местом). Есть ли более быстрый способ поиска строки в файле или просто это невозможно, и только БД может сделать лучше?
«включая некоторую конкатенацию строк, которая, я думаю, не должна быть узким местом», как именно вы выполняете конкатенацию строк?
Интересно, может быть более эффективно проверять, когда вы читаете файл, а не записывать его в список, а затем проверять по этому списку.
пиздец, все это не имеет значения. Если classes
— это контейнер на основе хэша, set
, то это не займет много времени. Это явно не так, почти наверняка list
Что-то вроде for line in open('classes.txt'): if any(word in line for word in words):
должно быть достаточно хорошо...
@Tomerikoo нет. это все еще полиномиальное время.
lines = fileObj.read().splitlines()
это не способ сделать это в Python. Просто используйте for line in fileObj: ...
Я действительно извиняюсь за отсутствие определения readFile. Только что добавил.
Просто сделайте это:
classes = set(readFile('classes.txt'))
(Или еще лучше, просто верните set
из вашей функции).
Тогда это больше не должно занимать 60 секунд, это должно быть практически мгновенно для 1000 слов.
Проблема в том, что вы проверяете:
word in classes
Но поскольку classes
— это список, это операция с линейным временем, поэтому в конечном итоге вы получаете полиномиальное время. Когда classes
является набором, это будет постоянное время.
Вот пример использования случайных строк:
In [1]: import string
In [2]: import random
In [3]: words = [''.join(random.sample(string.ascii_lowercase, 10)) for _ in range(1000)]
In [4]: classes = [''.join(random.sample(string.ascii_lowercase, 10)) for _ in range(100_000)]
In [5]: %%timeit
...: for word in words:
...: word in classes
...:
1.22 s ± 6.48 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Вы также смутно упомянули что-то о конкатенации строк. Вы также можете ввести поведение полиномиального времени, если сделаете это неправильно. Но вы этого не показали.
@Tomerikoo, конечно, суть все та же.
Зависит от того, есть ли несколько экземпляров одного и того же слова, что может иметь значение в других задачах, чем представленная.
спасибо за классный совет. Не могу поверить, что это только что увеличилось с 60 секунд до 1 секунды только с использованием set(). Спасибо!
Что такое
readFile
? Пожалуйста, предоставьте минимальный воспроизводимый пример. Вероятно, проблема в том, чтоreadFile
возвращает список слов. Вместо этого используйтеset
. Проверка 1000 слов вset
слов должна быть практически мгновенной.