例如:
>>> [1, 2, 3].contains_sequence([1, 2])
True
>>> [1, 2, 3].contains_sequence([4])
False
我知道in
运算符可以为字符串执行此操作:
>>> "12" in "123"
True
但我正在寻找可以迭代的东西。
答案 0 :(得分:4)
参考https://stackoverflow.com/a/6822773/24718 修改为使用列表。
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 = list(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + [elem]
yield result
def contains_sequence(all_values, seq):
return any(seq == current_seq for current_seq in window(all_values, len(seq)))
test_iterable = [1,2,3]
search_sequence = [1,2]
result = contains_sequence(test_iterable, search_sequence)
答案 1 :(得分:3)
是否内置了Python?不可以。您可以通过各种方式完成此任务。 Here is a recipe这样做,并且还给出了包含序列中子序列的位置:
def _search(forward, source, target, start=0, end=None):
"""Naive search for target in source."""
m = len(source)
n = len(target)
if end is None:
end = m
else:
end = min(end, m)
if n == 0 or (end-start) < n:
# target is empty, or longer than source, so obviously can't be found.
return None
if forward:
x = range(start, end-n+1)
else:
x = range(end-n, start-1, -1)
for i in x:
if source[i:i+n] == target:
return i
return None
答案 2 :(得分:2)
据我所知,没有办法做到这一点。你可以很容易地推出自己的功能,但我怀疑它会非常有效。
>>> def contains_seq(seq,subseq):
... #try: junk=seq[:]
... #except: seq=tuple(seq)
... #try: junk=subseq[:]
... #except: subseq=tuple(subseq)
... ll=len(subseq)
... for i in range(len(seq)-ll): #on python2, use xrange.
... if(seq[i:i+ll] == subseq):
... return True
... return False
...
>>> contains_seq(range(10),range(3)) #True
>>> contains_seq(range(10),[2,3,6]) #False
请注意,此解决方案不适用于生成器类型对象(它仅适用于您可以切片的对象)。您可以检查seq
以查看它是否可切片,然后继续并转换为tuple
,如果它不可切片 - 但是您可以摆脱切片的好处。您可以重新编写它以一次检查一个元素而不是使用切片,但我感觉性能会受到更大的影响。
答案 3 :(得分:2)
正如其他人所说的那样,没有内置因素。这是一个可能比我见过的其他答案更有效的实现 - 特别是,它扫描迭代,只是跟踪它所看到的目标序列的前缀大小。但是,与提出的其他一些方法相比,提高效率需要付出一些代价。
def contains_seq(iterable, seq):
"""
Returns true if the iterable contains the given sequence.
"""
# The following clause is optional -- leave it if you want to allow `seq` to
# be an arbitrary iterable; or remove it if `seq` will always be list-like.
if not isinstance(seq, collections.Sequence):
seq = tuple(seq)
if len(seq)==0: return True # corner case
partial_matches = []
for elt in iterable:
# Try extending each of the partial matches by adding the
# next element, if it matches.
partial_matches = [m+1 for m in partial_matches if elt == seq[m]]
# Check if we should start a new partial match
if elt==seq[0]:
partial_matches.append(1)
# Check if we have a complete match (partial_matches will always
# be sorted from highest to lowest, since older partial matches
# come before newer ones).
if partial_matches and partial_matches[0]==len(seq):
return True
# No match found.
return False
答案 4 :(得分:2)
如果不需要保留顺序,可以使用集合(内置):
>>> set([1,2]).issubset([1,2,3])
True
>>> set([4]).issubset([1,2,3])
False
否则:
def is_subsequence(sub, iterable):
sub_pos, sub_len = 0, len(sub)
for i in iterable:
if i == sub[sub_pos]:
sub_pos += 1
if sub_pos >= sub_len:
return True
else:
sub_pos = 0
return False
>>> is_subsequence([1,2], [0,1,2,3,4])
True
>>> is_subsequence([2,1], [0,1,2,3,4]) # order preserved
False
>>> is_subsequence([1,2,4], [0,1,2,3,4])
False
这个适用于任何迭代器。
答案 5 :(得分:1)
deque似乎在这里很有用:
from collections import deque
def contains(it, seq):
seq = deque(seq)
deq = deque(maxlen=len(seq))
for p in it:
deq.append(p)
if deq == seq:
return True
return False
请注意,这会接受两个参数的任意迭代(不需要切片)。
答案 6 :(得分:0)
由于没有内置,我做了一个很好的版本:
import itertools as it
def contains(seq, sub):
seq = iter(seq)
o = object()
return any(all(i==j for i,j in zip(sub, it.chain((n,),seq,
(o for i in it.count())))) for n in seq)
此不需要任何额外的列表(如果您使用it.izip
或Py3k)。
>>> contains([1,2,3], [1,2])
True
>>> contains([1,2,3], [1,2,3])
True
>>> contains([1,2,3], [2,3])
True
>>> contains([1,2,3], [2,3,4])
False
如果您在阅读时没有问题,请加分。 (它完成了这项工作,但实施不应过于严肃)。 ;)
答案 7 :(得分:-2)
您可以将其转换为字符串,然后在其上进行匹配
full_list = " ".join([str(x) for x in [1, 2, 3]])
seq = " ".join([str(x) for x in [1, 2]])
seq in full_list