问题描述
我有一个从 ak 返回的二进制列表表示 k = 2 的分类,我正在尝试 1) 识别 0,... 给定长度的子串的数量 - 至少说长度为 3 和 2) 标识这些子列表的开始和结束位置,因此在列表:L = [1,1,0]
中,理想情况下输出将是:number = 2
和 start_end_locations = [[2,6],[13,15]]
。
我正在使用的列表有数万个元素,因此我需要找到一种计算速度快的方法来执行此操作。我在 groupby
中看到了许多使用 itertools
的帖子,但我找不到将它们应用于我的任务的方法。
预先感谢您的建议!
解决方法
预先感谢您的建议!
- 制作与您的模式匹配的 regular expression:三个或多个零
- 连接列表项为字符串
- 使用 re.finditer 和匹配对象的 start() 和 end() 方法构建索引列表
将列表连接到一个字符串可能是最昂贵的部分 - 除非您尝试,否则您不会知道; finder 应该很快。需要多次通过数据,但可能工作量编码。
这可能会更好 - 单次遍历列表,但您需要注意逻辑 - 更努力地编写代码。
- 使用 enumerate 遍历列表
- 当您发现零
- 捕获它的索引和
- 设置一个标志,表明您正在跟踪零
- 当你找到一个一个
- 如果您要跟踪零
- 捕获索引
- 如果连续零的长度符合您的标准捕获该零的开始和结束索引
- 根据需要重置标志和中间变量
- 如果您要跟踪零
与 word 版本有点不同:
def g(a=a):
y = []
criteria = 3
start,end = 0,0
prev = 1
for i,n in enumerate(a):
if not n: # n is zero
end = i
if prev: # previous item one
start = i
else:
if not prev and end - start + 1 >= criteria:
y.append((start,end))
prev = n
return y
,
您可以使用 zip() 依次检测 1,0 和 0,1 中断的索引。然后在中断索引上使用 zip() 以形成范围并提取以零开头并跨越至少 3 个位置的范围。
cp: cannot copy a directory <path-to-the-test-folder-in-temp> into itself,<path-to-the-test-folder-in-temp/image/home/first>
输出:
def getZeroStreaks(L,minSize=3):
breaks = [i for i,(a,b) in enumerate(zip(L,L[1:]),1) if a!=b]
return [[s,e-1] for s,e in zip([0]+breaks,breaks+[len(L)])
if e-s>=minSize and not L[s]]
该函数可以泛化为查找列表中任何值的条纹:
L = [1,1,0]
print(getZeroStreaks(L))
[[2,6],[13,15]]
from timeit import timeit
t = timeit(lambda:getZeroStreaks(L*1000),number=100)/100
print(t) # 0.0018 sec for 16,000 elements