получить строку между игнорируемыми словами эффективным (по времени) способом - PullRequest
0 голосов
/ 03 августа 2020

при условии, что у меня есть текст:

txt='A single house painted white with a few windows and a nice door in front of the park'

Я хотел бы удалить все первые слова, если они являются стоп-словами, и получить подстроку до первого стоп-слова.

желаемый результат : дом выкрашен в белый цвет

Я могу oop над списком:

txt='A single house painted white with a few windows and a nice door in front of the park'
stopwords = ['a','the','with','this','is','to','etc'] # up to 250 words


for i,word in enumerate(txt.lower().split()):
    pos1= i
    if word in stopwords:
        break

rest_text = txt.split()[pos1+1:]
print(rest_text)
# and now we do the same for pos2

for i,word in enumerate(rest_text):
    pos2= i
    if word in stopwords:
        print(word,pos2)
        break

rest_text = rest_text[:pos2]
print(rest_text)

Я должен делать это для тысяч текстов, и скорость важна. зацикливание никогда не приводит к go в python. Но я не могу придумать решение для понимания списка.

некоторая помощь?

ПРИМЕЧАНИЕ 1. Я сделал текст примера длиннее, чтобы прояснить результат ЗАМЕТКА 2: другой пример: txt = 'это второй текст , чтобы прояснить результат, который мне нравится' результат: «второй текст»

1 Ответ

3 голосов
/ 03 августа 2020

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

set вместо list

Ваш код должен проверять, есть ли строка является участником stopwords лота. Список - не лучшая структура данных для этого, поскольку в худшем случае он требует сравнения с каждым элементом в списке. Тест на членство для списка - O (n).

set s намного быстрее выполняют этот тест членства. Их реализация в Python представляет собой что-то вроде ha sh table , что означает, что они могут выполнять проверку принадлежности за постоянное время, O (1). Таким образом, для большого количества элементов set будет значительно превосходить list для этой конкретной операции.

Вы можете создать set из stopwords вместо списка с:

stopwords = set(['a','the','with','etc'])

re.finditer вместо str.split()

Если ваш txt большой, и вам требуется только первая подходящая подстрока вашего txt (как подразумевается в вопросе), то вы можете добиться большей производительности, используя re.finditer вместо str.split() для разделения слов вашего текста.

str.split() возвращает список слов из всего текста в один раз, тогда как re.finditer возвращает итератор, который может выдавать слова по мере необходимости. В худшем случае вам, очевидно, все равно понадобится 'l oop' по всему тексту, но если ваши совпадения близки к началу txt, экономия времени и памяти может быть значительной.

Для пример:

txt='A single house painted white with a few windows'
stopwords = set(['a','the','with','etc'])

import re

split_txt = (match.group(0) for match in re.finditer(r'\S+', txt))

result = []
word = next(split_txt)

while word.lower() in stopwords:
    word = next(split_txt)

while word.lower() not in stopwords:
    result.append(word)
    word = next(split_txt)

print(' '.join(result))

Обратите внимание, что часто лучше просто начать с некоторого кода, который работает для проверки ваших входных данных, чем преждевременно начинать оптимизацию. Тестирование покажет, нужна ли оптимизация. Вы говорите в вопросе, что

цикл никогда не является способом go в Python

, но это просто неверно. Зацикливание в той или иной форме на любом языке чаще всего неизбежно. Хотя производительность может не соответствовать производительности скомпилированных языков, таких как C или Fortran, Python может удивить вас своей производительностью (если вы позволите)

...