我有一个包含很多bool
值的列表,我想得到这个模式:True, True, False, True, True
. 为此,我认为我需要在处理我的前一个元素时循环获取下一个元素。我该怎么做?
额外的问题:有没有办法增加列表中元素的位置而不是i += 1
事物?
我会尝试一下:
subset = [True, True, False, True, True]
main = [False, True, False, True, True, True, False, True, True, False, True, False, True]
for i, j in enumerate(xrange(len(subset), len(main) + 1)):
if main[i:j] == subset:
print subset, 'is at', i
break
else:
print 'not found'
注意:这有点粗暴,但一次性还可以……否则,看看尝试……
l = len(some_list) - 3
for i, thing in enumerate(some_list):
if i == l: break
if thing and some_list[i+1] and not some_list[i+2] and some_list[i+3]:
bingo(i)
另一个未经测试的尝试:
needle = [True, True, False, True, True]
needle_len = len(needle)
for i in range(len(stack)-needle_len+1):
if needle == stack[i:i+needle_len]:
bingo(i)
如果我正确理解了这个问题,那么您尝试做的事情与 完全相同str.find
,但是在列表中查找子列表而不是字符串中的子字符串。
如果是这样:
def findSubList(l, sub):
return (''.join('T' if x else 'F' for x in l)
.find(''.join('T' if x else 'F' for x in sub)))
这可能看起来很 hacky,但它是有道理的:你想在一个列表中找到一个子列表,两者都可以简单地转换为字符串,并且已经有一个内置函数可以在字符串中找到一个子字符串,所以为什么不使用吗?
结果可能太慢了,但实际上,编写它的速度非常快,值得对其进行测试,看看它是否对您的目的来说太慢了。(即使它太慢了,也可能是转换为字符串的部分很慢,首先使用字符串而不是布尔列表可能是合理的,或者在开始进行 200 次搜索之前转换一次, 管他呢。)
如果这不可避免地太慢了,我接下来要做的是查看实现str.find
并将其转换为通用序列查找。你已经有了 Python 的源代码,所以这应该不会太难。但是,它可能str.find
在 C 中,移植起来可能会很痛苦。在这种情况下,您可能仍想在线搜索纯 Python str.find
……但假设您没有找到。
下一步是查看 PyPI 上是否有序列查找模块。
如果没有,有一些众所周知的算法要么易于实现,要么在 ActiveState 甚至 Wikipedia 等地方免费实现。有关列表和一些比较,请参阅Wikipedia 上的字符串搜索算法。(性能特征取决于您没有提供给我们的因素——您需要进行多少次搜索;主要、子集或两者都不同;等等,这意味着没有更多信息,没有人能猜出哪个是最好的。)
甚至标准的字符串搜索算法也可能不够快,并且利用您搜索单个位而不是 8 位字符的事实可以获得主要的效率提升。(如果模式是固定的,您甚至应该能够将搜索描述为有限状态机,并将其转换为硬编码、可证明的最佳实现……)
因此,您可能必须自己设计一些东西。但你不太可能这样做,如果可能的话,我会避免这样做。每当你遇到一个明显常见的问题时,值得假设它是一个已解决的问题并寻找解决方案,而不是试图从第一原则解决它。
相当有效,使用滑动窗口方法,应该以线性时间运行。
def find_x_in_y(subset, main):
""" Returns a list of the indexes of the first value of matches. """
results = []
for i in xrange(len(main)):
if main[i:i+5] == subset:
results.append(i)
return results
# values borrowed from @JonClements
subset = [True, True, False, True, True]
main = [False, True, False, True, True, True, False, True, True, False, True, False, True]
>>> find_x_in_y(subset, main)
... [4]
@abarnert 很好,这是一种实际上非常有效的方法。
效率极高,将整个布尔列表转换为位数组并运行本机搜索方法。
from bitarray import bitarray
def find_x_in_y(subset, main):
subarray = bitarray(subset)
mainarray = bitarray(main)
return [int(i) for i in mainarray.itersearch(subarray)]
timeit
结果:
Length of main: 10 100 1000 10000 100000 1000000
returning _all_ matches:
# number of matches 1 10 100 1000 10000 100000
# sliding window approach (0.00059, 0.00502, 0.04194, 0.26211, 2.55554, 26.21962)
# bitarray approach (0.00028, 0.00072, 0.00484, 0.02926, 0.2822, 2.93676)
returning first match:
# sliding window approach (0.00034, 0.00034, 0.00034, 0.00021, 0.00026, 0.00059)
# bitarray approach (0.00017, 0.00017, 0.00016, 0.00011, 0.00014, 0.00049)
# joined string approach (0.00134, 0.00721, 0.06244, 0.39224, 4.21628, 39.63207)