【问题标题】:Finding locations of repeated 0 in a binary list在二进制列表中查找重复 0 的位置
【发布时间】:2021-03-10 16:16:29
【问题描述】:

我有一个从 k = 2 的 k 表示分类返回的二进制列表,我正在尝试 1) 识别给定长度的 0,0,0,... 子串的数量 - 比如说至少长度为 3 和 2) 标识这些子列表的开始和结束位置,因此在列表中:L = [1,1,0,0,0,0,0,1,1,1,0,0,1,0,0,0],理想的输出是:number = 2start_end_locations = [[2,6],[13,15]]。 我正在使用的列表包含数万个元素,因此我需要找到一种计算速度快的方法来执行此操作。我已经看到很多使用来自itertoolsgroupby 的帖子,但我找不到将它们应用于我的任务的方法。 提前感谢您的建议!

【问题讨论】:

    标签: python list group-by binary itertools


    【解决方案1】:

    提前感谢您的建议!

    • 制作与您的模式匹配的regular expression三个或更多零
    • 连接列表项到一个字符串
    • 使用 re.finditer 和匹配对象 start() 和 end() 方法构造索引列表

    将列表连接到一个字符串可能是最昂贵的部分 - 除非你尝试过,否则你不会知道; finditer 应该很快。需要不止一次遍历数据,但可能努力编写代码。


    这可能会更好 - 单次遍历列表,但您需要注意逻辑 - 编码更多。

    • 使用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
    

    【讨论】:

      【解决方案2】:

      您可以使用 zip() 依次检测 1,0 和 0,1 中断的索引。然后在中断索引上使用 zip() 来形成范围并提取以零开头并跨越至少 3 个位置的范围。

      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,0,0,0,0,1,1,1,0,0,1,0,0,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
      

      该函数可以泛化为查找列表中任何值的条纹:

      def getStreaks(L,N=0,minSize=3):
          breaks = [i for i,(a,b) in enumerate(zip(L,L[1:]),1) if (a==N)!=(b==N)]
          return [[s,e-1] for s,e in zip([0]+breaks,breaks+[len(L)])
                               if e-s>=minSize and L[s]==N]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-12-12
        • 2021-12-04
        • 2021-06-22
        • 2011-12-10
        • 2018-06-26
        • 2010-11-04
        • 2014-03-04
        相关资源
        最近更新 更多