【Python】使用bisect解决段落分割,快速找到所属分段

一、概念:什么是bisect?

bisect实质上是python自带的数组二分查找算法:bisect — 数组二分查找算法【官方文档】
因为本质是二分,所以需满足数组是【有序的】
以下是二分的内置算法:

def index(a, x):
    'Locate the leftmost value exactly equal to x'
    i = bisect_left(a, x)
    if i != len(a) and a[i] == x:
        return i
    raise ValueError

def find_lt(a, x):
    'Find rightmost value less than x'
    i = bisect_left(a, x)
    if i:
        return a[i-1]
    raise ValueError

def find_le(a, x):
    'Find rightmost value less than or equal to x'
    i = bisect_right(a, x)
    if i:
        return a[i-1]
    raise ValueError

def find_gt(a, x):
    'Find leftmost value greater than x'
    i = bisect_right(a, x)
    if i != len(a):
        return a[i]
    raise ValueError

def find_ge(a, x):
    'Find leftmost item greater than or equal to x'
    i = bisect_left(a, x)
    if i != len(a):
        return a[i]
    raise ValueError

二、基础段落分割案例

官方给出的案例:
bisect() 函数对于数字表查询也是适用的。 这个例子使用 bisect() 根据一组有序的数字划分点来查找考试成绩对应的字母等级: (如) 90 及以上为 ‘A’,80 至 89 为 ‘B’,依此类推:

>>>def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
       i = bisect(breakpoints, score)
       return grades[i]

>>>[grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
   ['F', 'A', 'C', 'C', 'B', 'A', 'A']

三、实用案例

问题描述:
每天白班是6:45-18:45夜班是18:45-次日6:45
给出当前时间班次和上一班次的开始时间和结束时间

不采用bisect,使用if和else需要考虑0点到6点的情况,单独增加判断,代码if-else分支较多,代码逻辑比较冗余:

def get_shift_times(turn: int) -> TurnTimeVo:
    current_time = datetime.now()
    today = current_time.date()
    yesterday = today - timedelta(days=1)
    tomorrow = today + timedelta(days=1)
    # 一天开始的时间
    today_start_time = datetime.strptime(Constants.TODAY_START_TIME, "%H:%M:%S").time()
    # 白班开始时间
    day_start = datetime.strptime(Constants.WORK_SHIFT_START_TIME, "%H:%M:%S").time()
    # 白班结束时间
    day_end = datetime.strptime(Constants.WORK_SHIFT_END_TIME, "%H:%M:%S").time()
    # 时间段分割
    today_start = datetime.combine(today, today_start_time)
    today_day_start = datetime.combine(today, day_start)
    today_day_end = datetime.combine(today, day_end)
    yesterday_day_start = datetime.combine(yesterday, day_start)
    yesterday_day_end = datetime.combine(yesterday, day_end)
    tomorrow_day_start = datetime.combine(tomorrow, day_start)

    if turn == TurnShift.now_turn:  # 当前班次
        if current_time >= today_start and current_time <= today_day_start:
            shift_start = yesterday_day_end
            shift_end = today_day_start
        elif current_time > today_day_start or current_time <= today_day_end:
            shift_start = today_day_start
            shift_end = today_day_end
        else:
            shift_start = today_day_end
            shift_end = tomorrow_day_start
    elif turn == TurnShift.last_turn:  # 上一班次
        if current_time >= today_start and current_time <= today_day_start:
            shift_start = yesterday_day_start
            shift_end = yesterday_day_end
        elif current_time > today_day_start or current_time <= today_day_end:
            shift_start = yesterday_day_end
            shift_end = today_day_start
        else:
            shift_start = today_day_start
            shift_end = today_day_end
    else:
        raise ValueError("Invalid turn value. Please provide 1 or 2.")
    vo = TurnTimeVo(start_time=shift_start, end_time=shift_end)
    return vo

采用bisect之后逻辑更为清晰:

def get_shift_times(turn: int) -> TurnTimeVo:
    current_time = datetime.now()
    today = current_time.date()
    yesterday = today - timedelta(days=1)
    tomorrow = today + timedelta(days=1)
    # 白班开始时间
    day_start = datetime.strptime(Constants.WORK_SHIFT_START_TIME, "%H:%M:%S").time()
    # 白班结束时间
    day_end = datetime.strptime(Constants.WORK_SHIFT_END_TIME, "%H:%M:%S").time()
    # 时间段分割
    today_day_start = datetime.combine(today, day_start)
    today_day_end = datetime.combine(today, day_end)
    yesterday_day_start = datetime.combine(yesterday, day_start)
    yesterday_day_end = datetime.combine(yesterday, day_end)
    tomorrow_day_start = datetime.combine(tomorrow, day_start)

    brakpoints = [
        yesterday_day_start,
        yesterday_day_end,
        today_day_start,
        today_day_end,
        tomorrow_day_start,
    ]
    current_interval_index = bisect.bisect(brakpoints, current_time)

    if turn == TurnShift.now_turn:  # 当前班次
        shift_start = brakpoints[current_interval_index - 1]
        shift_end = brakpoints[current_interval_index]
    elif turn == TurnShift.last_turn:  # 上一班次
        shift_start = brakpoints[current_interval_index - 2]
        shift_end = brakpoints[current_interval_index - 1]
    else:
        raise ValueError("Invalid turn value. Please provide 1 or 2.")

    vo = TurnTimeVo(start_time=shift_start, end_time=shift_end)
    return vo
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值