Python - 元组 + 二分法(bisect)优化多分支代码

目录

一、应用实例

二、bisect 学习


一、应用实例

有时,我们的代码里会出现超过三个分支的 if/else 。就像下面这样:

import time


def from_now(ts):
    """接收一个过去的时间戳,返回距离当前时间的相对时间文字描述
    """
    now = time.time()
    seconds_delta = int(now - ts)
    if seconds_delta < 1:
        return "less than 1 second ago"
    elif seconds_delta < 60:
        return "{} seconds ago".format(seconds_delta)
    elif seconds_delta < 3600:
        return "{} minutes ago".format(seconds_delta // 60)
    elif seconds_delta < 3600 * 24:
        return "{} hours ago".format(seconds_delta // 3600)
    else:
        return "{} days ago".format(seconds_delta // (3600 * 24))


now = time.time()
print(from_now(now))
print(from_now(now - 24))
print(from_now(now - 600))
print(from_now(now - 7500))
print(from_now(now - 87500))
# OUTPUT:
# less than 1 second ago
# 24 seconds ago
# 10 minutes ago
# 2 hours ago
# 1 days ago

上面这个函数挑不出太多毛病,很多很多人都会写出类似的代码。但是,如果你仔细观察它,可以在分支代码部分找到一些明显的“边界”。比如,当函数判断某个时间是否应该用“秒数”展示时,用到了 60。而判断是否应该用分钟时,用到了 3600

从边界提炼规律是优化这段代码的关键。如果我们将所有的这些边界放在一个有序元组中,然后配合二分查找模块 bisect

整个函数的控制流就能被大大简化:

import bisect


# BREAKPOINTS 必须是已经排好序的,不然无法进行二分查找
BREAKPOINTS = (1, 60, 3600, 3600 * 24)
TMPLS = (
    # unit, template
    (1, "less than 1 second ago"),
    (1, "{units} seconds ago"),
    (60, "{units} minutes ago"),
    (3600, "{units} hours ago"),
    (3600 * 24, "{units} days ago"),
)


def from_now(ts):
    """接收一个过去的时间戳,返回距离当前时间的相对时间文字描述
    """
    seconds_delta = int(time.time() - ts)
    unit, tmpl = TMPLS[bisect.bisect(BREAKPOINTS, seconds_delta)]
    return tmpl.format(units=seconds_delta // unit)

除了用元组可以优化过多的 if/else 分支外,有些情况下字典也能被用来做同样的事情。关键在于从现有代码找到重复的逻辑与规律,并多多尝试。

二、bisect 学习

bisect- 数组二分算法 - 官方文档

import bisect

# 等同于 bisect_right
# bisect.bisect(a, x, lo=0, hi=None)
# 返回要在列表a中插入项目x的索引,假设a已排序。 - 返回小于并最接近x的索引
# 返回值i是这样的:a[:i]中的所有e都有e <= x, a[i:]中的所有e都有e > x。
# 可选的args lo(默认0)和hi(默认len(a))绑定要搜索的a片。

li = [1, 2, 3, 4, 5]
a = bisect.bisect(li, 3.6)
print(a)

# 3

猜你喜欢

转载自blog.csdn.net/qq_33961117/article/details/88948629