簡體   English   中英

如何在兩個不同的列表中“減去”重疊的元組時間范圍

[英]How to 'subtract' overlapping tuple time ranges in two different lists

我有兩個元組列表,每個元組由一個開始和結束時間(從紀元開始的秒數)組成,如下所示:

list1= [(2,4), (7,10), (14,22)]

list2 = [(1,3), (5,8), (9,15), (20,24)]

我需要創建一個新的元組(開始,結束)范圍列表,以刪除list2的元組與list1的元組重疊的時間間隔。

給定list1list2 ,該方法的預期輸出為:

[(3,4), (8,10), (15,20)]

就其價值而言,列表list1和列表list2都將包含唯一的時間范圍,即每個單獨的列表內都不會重疊。

這是一個僅在列表的每個元素上迭代一次的解決方案。

使用list1 = [(2, 4), ...]list2 = [(1, 3), ...] ,我們得到:

  • 從1開始,已刪除部分的開始
  • 在2開始
  • 在3,已刪除部分的末尾
  • 在4,間隔結束時

輸出是由我們都在區間內而不是在已刪除部分中的部分組成的。

因此,我們的想法是按順序瀏覽事件,跟蹤我們是否處於間隔中以及是否位於已刪除的部分中。

我們從每個列表創建一個生成器開始,它將生成:

  • 對於第一個Event(pos=2, toggle='in_interval')Event(pos=2, toggle='in_interval')Event(pos=4, toggle='in_interval')等。
  • 對於第二個Event(pos=1, toggle='in_deleted')Event(pos=1, toggle='in_deleted')Event(pos=3, toggle='in_deleted') ...

我們不需要關心每個值是間隔的開始還是結束,因為它只是在切換狀態(間隔的內部/外部)。

然后,我們可以使用heapq.merge從這兩個生成器中按順序獲取事件,這將為我們提供以下信息:

Event(pos=1, toggle='in_deleted')Event(pos=2, toggle='in_interval')Event(pos=3, toggle='in_deleted')Event(pos=4, toggle='in_interval') ...

每個事件將切換關聯的狀態。 當我們既處於間隔中又不在刪除的部分中時,我們將為輸出創建一個新的間隔。 其余的不言而喻...

from heapq import merge
from itertools import chain
from collections import namedtuple

def remaining(intervals, deleted):
    Event = namedtuple('Event', ['position', 'toggle'])

    int_iter = (Event(position=pos, toggle='in_interval') for pos in chain.from_iterable(intervals))
    del_iter = (Event(position=pos, toggle='in_deleted') for pos in chain.from_iterable(deleted))

    state = {'in_interval': False, 'in_deleted': False}
    start = None
    out = []

    for event in merge(int_iter, del_iter):
        state[event.toggle] = not state[event.toggle]
        if state['in_interval'] and not state['in_deleted']:
            # start a new interval
            start = event.position
        elif start is not None:
            # end an interval. If it's not empty, we append it to the output
            if event.position > start:
                out.append((start, event.position))
            start = None
    return out

輸出示例:

list1 = [(2,4), (7,10), (14,22)]
list2 = [(1,3), (5,8), (9,15), (20,24)]      

print(remaining(list1, list2))
# [(3, 4), (8, 9), (15, 20)]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM