Существует в основном три варианта: линейное сканирование списка в O (n), ...
>>> lst = random.sample(range(1, 1000000), 100000)
>>> x = lst[50000]
>>> %timeit x in lst
100 loops, best of 3: 2.12 ms per loop
... двоичный поиск в отсортированном списке в O (logn) с использованием модуля bisect
, ...
>>> srt = sorted(lst)
>>> srt[bisect.bisect_left(srt, x)] == x
True
>>> %timeit srt[bisect.bisect_left(srt, x)] == x
1000000 loops, best of 3: 444 ns per loop
... и поиск в хэше set
в O (1):
>>> st = set(lst)
>>> %timeit x in st
10000000 loops, best of 3: 38.3 ns per loop
Очевидно, что set
является самым быстрым, но он также занимает немного больше памяти, чем подходы, основанные на list
. Подход bisect
может быть хорошим компромиссом: он уже в 5000 раз быстрее линейного сканирования в этом примере и требует только сортировки списка.
>>> sys.getsizeof(lst)
800064
>>> sys.getsizeof(srt)
900112
>>> sys.getsizeof(st)
4194528
Однако, если ваш компьютер не очень ограничен в памяти, это не должно быть проблемой. В частности, это не сделает код медленнее. Либо все это помещается в память, и все хорошо, либо нет, и ваша программа останавливается.
Если ваши списки хороших / плохих слов могут содержать дубликаты, то set
не вариант, и bisect
тоже не будет работать. В этом случае создайте Counter
для каждого из этих списков. Затем вы можете получить количество вхождений и частоты для каждой из подстрок в вашем тексте. Будучи своего рода хэш-картой / словарем, поиск в Counter
также будет O (1).
>>> clean_x_list = ['ap','pp','pl','le','bo','xl','ap']
>>> w = "apple"
>>> wx = [w[i:i+2] for i in range(len(w)-1)]
>>> ccx = collections.Counter(clean_x_list)
>>> occ_wx = {x: ccx[x] for x in wx}
>>> occ_wx
{'ap': 2, 'pp': 1, 'pl': 1, 'le': 1}
>>> freq_wx = {x: ccx[x] / len(clean_x_list) for x in wx}
>>> freq_wx
{'ap': 0.2857142857142857,
'pp': 0.14285714285714285,
'pl': 0.14285714285714285,
'le': 0.14285714285714285}
И аналогично для clean_y_list
, bad_x_list
и т. Д.