Python:区间映射到值

25 投票
6 回答
13148 浏览
提问于 2025-04-15 13:14

我正在重构一个函数,这个函数的作用是:给定一系列的端点,这些端点隐含地定义了一些区间,然后检查一个数字是否在这些区间内,最后返回一个对应的值(这个值和计算没有任何关系)。

现在处理这个工作的代码是:

if p <= 100:
    return 0
elif p > 100 and p <= 300:
    return 1
elif p > 300 and p <= 500:
    return 2
elif p > 500 and p <= 800:
    return 3
elif p > 800 and p <= 1000:
    return 4
elif p > 1000:
    return 5

我觉得这个代码写得很糟糕,而且问题在于这些区间和返回的值都是写死在代码里的。

当然,你可以使用任何数据结构来解决这个问题。

6 个回答

3

这确实挺糟糕的。如果没有要求不写死代码,它应该是这样写的:

if p <= 100:
    return 0
elif p <= 300:
    return 1
elif p <= 500:
    return 2
elif p <= 800:
    return 3
elif p <= 1000:
    return 4
else:
    return 5

这里有一些创建查找函数的例子,包括线性查找和二分查找,满足不写死代码的要求,并且对这两个表进行了几个合理性检查:

def make_linear_lookup(keys, values):
    assert sorted(keys) == keys
    assert len(values) == len(keys) + 1
    def f(query):
        return values[sum(1 for key in keys if query > key)]
    return f

import bisect
def make_bisect_lookup(keys, values):
    assert sorted(keys) == keys
    assert len(values) == len(keys) + 1
    def f(query):
        return values[bisect.bisect_left(keys, query)]
    return f
3

你可以试试这样做:

def check_mapping(p):
    mapping = [(100, 0), (300, 1), (500, 2)] # Add all your values and returns here

    for check, value in mapping:
        if p <= check:
            return value

print check_mapping(12)
print check_mapping(101)
print check_mapping(303)

这样会产生:

0
1
2

在Python中,总会有更好的方法来实现这个。

56
import bisect
bisect.bisect_left([100,300,500,800,1000], p)

这里是文档链接: bisect

撰写回答