如何在python中找到重叠时间

时间:2015-05-20 10:47:09

标签: python algorithm

我很长时间没有找到如何在python中拆分重叠时间的逻辑。

这是我的测试用例时间

  1. 上午9点 - 下午5点
  2. 上午8点至10点,下午12点至下午1点,下午4点至下午6点(多个参赛作品)
  3. 案例1:

    Entry 1: 9am - 5pm
    Test Entry: 10am - 12pm
    Output: 9am - 10am,  10am - 12pm, 12pm - 5pm
    

    现在我希望如果输入重叠时间,那么系统应该将它分成不同的时间。像

    entry1.start_time = 9:00am
    entry1.end_time = 5:00pm
    

    现在,如果我输入此条目

    entry2.start_time = 10:00am
    entry2.end_time = 12:00pm
    

    然后系统应将其拆分为

    9am - 10am, 10am - 12pm, 12pm - 5pm

    案例2

    Entry 1 - 9am - 5pm
    Test Entry    8am - 10am
    Then output should be   8am - 10am ,   10am - 5pm
    

    案例3 这是案例1的启示

    Entry 1 - 9am - 10am

    Test Entry 8am - 11am

    Then output should be   8am - 11am
    

    我陷入逻辑困境。这是我开始的一些代码

    class TimeSplitter(object):
        def __init__(self, **kwargs):
            self.entries = kwargs.pop('entries', [])
            self.test_entry = kwargs.pop('testEntry', '')
    
        def test_overlap(self, entry1, test_entry):
            if test_entry.start_time > entry1.start_time and  test_entry.start_time < entry1.end_time
            pass
    

    我无法继续下去

3 个答案:

答案 0 :(得分:1)

<强> Prelimininaries

鉴于您的示例案例,您希望区分基本条目的测试条目间隔,即在算法的结果中不应分割测试条目间隔。

我将首先在更一般的设置中描述解决方案,其中基本和测试输入间隔被视为相同。然后将补充此解决方案以满足保留的测试条目。

此补充假设测试输入间隔不重叠。第二个修改确保在运行算法之前,在概念上将重叠的测试条目间隔折叠为单个间隔。

<强>买者

此解决方案不提供收缩包装的python实现,而是伪代码。把它变成有效的python应该是直截了当的。

<强>概要

原始时间间隔涵盖当天p的某一部分。 p是这些间隔的结合。注意这个联合是一组有序的非重叠区间。

基本思想是通过一组满足3个条件的不同时间间隔来覆盖p

  • 时间间隔精确覆盖p
  • 间隔不重叠
  • 原始集的间隔边界必须是新集合的间隔内部元素。

考虑原始区间集的边界时间集。该集合中的元素按规范排序。构建由该集合中的相邻时间点定义的一系列间隔。结果是包含p的非空间隔的无间隙并置。

由于p可能是非连续的,因此构造的序列必须与p相交才能获得最终结果。这个交叉点没有 从计算集中改变任何间隔;但是,它可能会消除一些。

算法(一般)

  • 在列表tl_ta中收集所有时间间隔边界。 tl_ta的元素应该是实际时间的对,以及指示元素是区间的开始还是结束的标志。此标记将用于跟踪p

  • 中的差距
  • 按元素对的第一个组件

  • 对列表进行排序
  • 迭代排序的时间点列表,构建非重叠区间的结果列表。

    要实现这一目标,你需要......

    • 结果列表tl_cover(最初为空)。
    • 当前和上一个迭代元素ta_currentta_previous
    • 一个计数器cnt_active,指示当前时间点包含的间隔数(最初为0)。

    在迭代的每个步骤中,执行以下操作:

    • 如果当前和之前的时间点不同并且有一些活动间隔,请在结果列表中按下新的时间间隔:

      if (ta_previous[0] != ta_current[0]) && cnt_active > 0 then tl_cover.push ( [ta_previous[0], ta_current[0]] ); end if

    • 如果当前时间是间隔开始,则递增有效间隔的计数器:
      if ta_current[1] then cnt_active++; end if;
    • 如果当前时间是间隔结束,则递减有效间隔的计数器:
      if !ta_current[1] then cnt_active--; end if;
    • 更新当前和之前的时间点:
      ta_previous = ta_current; ta_current = shift tl_ta;

算法(补码1 - 稳定的测试输入间隔)

为了保持测试条目的间隔不变,在迭代期间保持一个标志b_preserve,表示测试条目间隔当前是否有效。虽然如此,但不会终止新的间隔。

因此tl_ta的元组成为三元组,第三个元素表示这个时间点是否来自测试条目。处理测试条目开始/结束时间设置/重置b_preserve

tl_ta应按字典顺序排序,比较元组(tl_ta[_][0], !tl_ta[_][1], tl_ta[_][1] ? tl_ta[_][2] : !tl_ta[_][2]),以便在相同的时间,......

  • ...首先处理上限区间
  • ...在较低的间隔范围内,首先处理测试条目边界
  • ...在上部区间界限中,最后处理测试条目边界

此约定可防止具有共同边界的多个测试和基本输入间隔之间的干扰。

每次迭代的第一步现在还检查测试条目包含:

 if (ta_previous[0] != ta_current[0]) && (cnt_active > 0) && !b_preserve then
     tl_cover.push ( [ta_previous[0], ta_current[0]] );
 end if

新变量与活动间隔计数器一起维护:

 if ta_current[2] then
     b_preserve = ta_current[1];
 end if;

算法(补码2 - 重叠测试输入间隔)

而不是布尔值b_preserve使用初始化为0的计数器cnt_active_te来处理重叠。每次迭代的新检查的第一步:

 if (ta_previous[0] != ta_current[0]) && (cnt_active > 0) && (cnt_active_te == 0) then
     tl_cover.push ( [ta_previous[0], ta_current[0]] );
 end if

维护cnt_active_te而不是b_preserve

 if ta_current[2] then
     cnt_active_te += ta_current[1] ? 1 : -1;
 end if;

答案 1 :(得分:0)

通常情况下 - 给出一个完整的代码并不是一个好主意 - 我同意 - 但是这里看起来像是有效的。基本的想法是 1)首先将input_start转到test_start(如果它们都不相等且input_start为min) 2)总是采用test_start和test_end 3)如果test_end小于输入结束(并且end_input和end_test不相等),则将test_end带到input_end。

下面的代码很少用铃铛和口哨。

def time_to_int(time_str, midnight_0=False):
    """ Converts a given time to an int. if midnight_0 is passed and is
    True, returns 0, instead of 24
    """
    time_str = time_str.lower()
    if time_str.find('am') > 0:
        return int(time_str.strip().strip('am'))
    elif time_str.find('pm') > 0:
        if midnight_0:
            return (12 + int(time_str.strip().strip('pm'))) % 24
        else :
            return (12 + int(time_str.strip().strip('pm')))
    else :
        return -1

def int_to_ampm(time):
    if(time <= 12):
        return str(time) + 'am'
    else:
        return str(time-12) + 'pm'

# throw in some tests for the above routine
#print time_to_int(' 9am')
#print time_to_int(' 9AM')
#print time_to_int(' 11Pm')
#print time_to_int('12pM\n')
#print int_to_ampm(12)
#print int_to_ampm(11)
#print int_to_ampm(17)

input_entries = ['9am - 5pm', '9am - 10am']
test_entries = ['10am - 12am', '8am - 10am', '8am - 11am']

for ip in input_entries:
    for test in test_entries:
        ip_1 = [time_to_int(x) for x in ip.split('-')]
        test_1 = [time_to_int(x) for x in test.split('-')]
        out_intervals = []
        start = min(ip_1[0], test_1[0])
        end = max(ip_1[1], test_1[1])
        if(start == ip_1[0]) and start != test_1[0]:
            out_intervals.append([start, test_1[0]])
        out_intervals.append(test_1)
        if(end == ip_1[1]) and (ip_1[1] != test_1[1]):
            out_intervals.append([test_1[1], end])
        print ip_1, test_1, "=>",  ["-".join(y) for y in [map(int_to_ampm, x) for x in out_intervals]]

答案 2 :(得分:-1)

以下是我要做的事情:

import time

Entry1 = "9am - 5pm"
Test_Entry = "10am - 12am"

#Split the test into hours
hours = Entry1.split(" - ")
Test_hours = Test_Entry.split(" - ")

#Convert the hours into time objects for comparison
hours24 = [ time.strptime(hour, '%I%p') for hour in hours]
Test_hours24 = [ time.strptime(hour, '%I%p') for hour in Test_hours]

#Case 1
if Test_hours24[0] >= hours24[0] and Test_hours24[1] <= hours24[1]:
    print time.strftime('%I%p',hours24[0]) + " - " + time.strftime('%I%p',Test_hours24[0]) + ",  " + time.strftime('%I%p',Test_hours24[0]) + " - " + time.strftime('%I%p',Test_hours24[1]) + ",  " + time.strftime('%I%p',Test_hours24[1]) + " - " + time.strftime('%I%p',hours24[1])

#Case 2
elif Test_hours24[0] <= hours24[0] and Test_hours24[1] <= hours24[1]:
    print time.strftime('%I%p',Test_hours24[0]) + " - " + time.strftime('%I%p',Test_hours24[1]) + ",  " + time.strftime('%I%p',Test_hours24[1]) + " - " + time.strftime('%I%p',hours24[1])

#Case 3
elif Test_hours24[0] <= hours24[0] and Test_hours24[1] >= hours24[1]:
    print time.strftime('%I%p',Test_hours24[0]) + " - " + time.strftime('%I%p',Test_hours24[1])

else:
    print "Error"