【问题标题】:Effecient way to iterate over two related loops in python在python中迭代两个相关循环的有效方法
【发布时间】:2019-05-05 17:17:58
【问题描述】:

我正在尝试遍历两个循环,第一个 segment_arr 是一条线的小段(例如 0.1m)列表(按沿线的距离排序),第二个 fail_sections 是一个列表该线的较大部分(例如5m)以某种方式“失败”(也按沿线的距离排序)。最终我试图合并浮点范围 - 有一些答案here,但都是基于整数和一些关于重叠的警告。

我有一个非常幼稚的版本,它的性能似乎足以满足我的目的,但它让我思考,如何才能提高效率:

new_seg_array = []
for seg in segment_arr:
        segfail = False
        for fail_sec in fail_sections:
            if seg.start_dist >= fail_sec.start_dist and seg.end_dist <= fail_sec.end_dist:
                segfail = True
        seg_data = Segment(start_dist=seg.start_dist,end_dist=seg.end_dist, does_fail=segfail)
        new_seg_array.append(seg_data)

主要问题是第二个循环浪费了迭代,因为第二个范围远远超出了我们在第一个范围内的位置,所以条件不可能为真。我考虑过使用生成器表达式,例如

filtered_fail_sections = (x for x in fail_sections where x.start_distance > seg.start_distance and x.end_distance < seg.end_distance)
for fail_sec in filtered_fail_sections:

过滤相关的失败段,但令我震惊的是,这只是在生成器中进行过滤工作。 Python中有没有办法逐渐减少第二个循环的范围,所以不再相关的元素因为它们超出了第一个循环的范围而不再迭代?所以随着时间的推移,第二个循环会变得更小,直到它什么都没有,这可能有助于在更大数据集上的性能。或者任何其他可能的重大效率改进?

【问题讨论】:

    标签: python performance loops


    【解决方案1】:

    您可以将当前“活动”的失败段存储在堆上,按其结束值排序,然后当该结束值小于当前段的结束时将它们从堆中弹出。然后,如果堆上有任何元素,则当前段失败。

    import heapq
    segments = [(1,2), (3,4), (5,7), (9,10)]
    fail = [(0,4), (8,11)]
    
    idx = 0
    covering = []
    for (start, end) in segments:
        while idx < len(fail) and fail[idx][0] <= start:
            heapq.heappush(covering, fail[idx][1])
            idx += 1
        while covering and covering[0] < end:
            heapq.heappop(covering)
        print(start, end, covering)    
    

    示例输出:

    1 2 [4]
    3 4 [4]
    5 7 []
    9 10 [11]
    

    这样,您不仅如果知道当前段失败,而且知道它与哪个失败段以及有多少失败段相交。请注意,如果要将完整的失败段放入堆中,则应使用元组 (end, f_seg) 以确保具有最低 end 的段在堆上排在第一位。

    当然,如果您不需要知道相交了哪些失败段或有多少失败段,则可以只跟踪任何已开始失败段的最大结束值,而无需使用堆。

    idx = 0
    last_fail = -1
    for (start, end) in segments:
        while idx < len(fail) and fail[idx][0] <= start:
            last_fail = max(last_fail, fail[idx][1])
            idx += 1
        print(start, end, last_fail >= end)
    

    对于 n 个段和 m 个失败段,基于堆的解决方案的复杂性将是 O(n+mlogm),并且只是O(n+m) 没有堆。 (假设两个列表都已排序。)

    【讨论】:

      猜你喜欢
      • 2021-07-05
      • 2017-03-06
      • 2018-04-09
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 2016-04-22
      • 1970-01-01
      相关资源
      最近更新 更多