У меня есть список значений:
a = [1,3,4,5,2]
Теперь мне нужна следующая функция:
does_segment_exist(a, [1,3,4]) #True
does_segment_exist(a, [3,4,5]) #True
does_segment_exist(a, [4,5,2]) #True
does_segment_exist(a, [1,4,5]) #False
does_segment_exist(a, [1,3]) #True
does_segment_exist(a, [1,4]) #False
Значения должны быть найдены в последовательном порядке.
У меня есть умный способ сделать это в Python 3?
Вы можете использовать итератор с катящимся окном, в этом случае один из старой версии itertools
docs:
from itertools import islice
def window(seq, n=2):
"Returns a sliding window (of width n) over data from the iterable"
" s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ... "
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
def does_segment_exist(iterable, sublist):
return tuple(sublist) in window(iterable, len(sublist))
print(does_segment_exist([1,3,4,5,2], [3,4,5]))
Если вам нужна только работа над списками, а не любая итерация, вы можете использовать:
def does_segment_exist(seq, sublist):
# seq and sublist must both be lists
n = len(sublist)
return sublist in (seq[i:i+n] for i in range(len(seq) + 1 - n))
Основная реализация метода, упомянутого Раймондом:
def does_segment_exist(seq, sublist):
first = sublist[0]
i = 0
n = len(sublist)
while True:
try:
i = seq.index(first, i)
except ValueError:
return False
if sublist == seq[i:i+n]:
return True
i += 1
print(does_segment_exist([1,3,4,5,2], [3,4,5]))
Преимущество этого метода заключается в том, что ему не нужно срезать для каждого индекса до первого совпадения только для индексов, соответствующих совпадениям для первого значения в сегменте.
Существует много способов сделать это, и они все изоморфны алгоритма поиска подстроки.
Самый простой способ - наивный поиск с помощью list.index(), чтобы найти общую начальную точку, а затем использовать срез для проверки полного соответствия. Если нет совпадения, повторите поиск, пока не попадете в конец списка.
Это должно работать с Python 2.5 и новее:
def does_segment_exist(sequence, segment):
n, m = len(sequence), len(segment)
return any(segment == sequence[i:i+m] for i in range(n+1-m))
in
только что автоматически делает ==
.