如何在不使用条件语句的情况下为值应用最大和最小边界

6 投票
10 回答
12189 浏览
提问于 2025-04-17 16:07

问题:

写一个Python函数,叫做clip(lo, x, hi),这个函数的功能是:如果x小于lo,就返回lo;如果x大于hi,就返回hi;否则就返回x。对于这个问题,你可以假设lo一定小于hi。

注意,这个问题不允许使用任何条件语句。相反,你需要使用Python内置的min和max函数。你可能需要先看看min和max的使用说明,并在你的解释器中试着玩一下这两个函数,然后再开始解决这个问题。

这个函数会接收三个数字,并返回一个数字。

给出的代码:

def clip(lo, x, hi):
    '''
    Takes in three numbers and returns a value based on the value of x.
    Returns:
     - lo, when x < lo
     - hi, when x > hi
     - x, otherwise
    '''

我添加的代码:

def clip(lo, x, hi):
    '''
    Takes in three numbers and returns a value based on the value of x.
    Returns:
     - lo, when x < lo
     - hi, when x > hi
     - x, otherwise
    '''
    if min(x, lo, hi) == x:
        return lo
    elif max(x, lo, hi) == x:
        return hi
    else:
        return x

问题是:我不能使用任何条件语句。求助!

10 个回答

3

我不想给出完整的解决方案,但你其实不需要“检查”什么。你可以用 max(x, lo) 这个方法来得到一个值,这个值不会低于 lo

另外,如果一个值已经被限制在某个范围内,那么再去限制它到另一个范围是不会有影响的。所以你可以放心地把一个修正后的结果再进行另一个修正。

9

这里有一个解决方案,假设 lo 小于 hi。

def clip(lo, x, hi):
    return max(lo, min(hi, x))

下面是每种情况的工作原理:

  • 当 x 小于 lo: 如果 lo 小于 hi,那么 x 也小于 hi,所以 min(hi, x) 会返回 x,而 max(lo, x) 会返回 lo
  • 当 x 大于 hi: min(hi, x) 会返回 hi,并且 如果 lo 小于 hi,那么 max(lo, hi) 也会返回 hi
  • 其他情况: x 大于 lo 并且小于 hi,所以 min(hi, x) 会返回 x,而 max(lo, x) 也会返回 x
8

目前你有几个选项可以选择。还有一个没提到的就是嵌套的三元表达式:

def clip(lo, x, hi):
    return lo if x <= lo else hi if x >= hi else x

不过因为这个使用了明确的条件测试,所以可能不太适合原来的问题。不过,在这些选项中,这个确实有个好处,就是如果 x <= lo,它可以快速结束(其他方法都要评估所有的比较和/或进行一到两个方法调用)。接下来我们来看看这些不同的方法在性能上表现如何,使用的是timeit(测试是在Python 3.3下进行的,所以range不会生成一个列表,而是返回一个迭代器):

python -m timeit -s "lo,hi=10,90" "[max(lo,min(hi,x)) for x in range(100)]"
10000 loops, best of 3: 54.5 usec per loop

(每次评估需要2次函数调用,性能很差)

python -m timeit -s "lo,hi=10,90" "[(lo,(hi,x)[x<hi])[x>lo] for x in range(100)]"
10000 loops, best of 3: 40.9 usec per loop

(评估了两个测试并为每次评估生成元组,但至少没有函数调用)

python -m timeit -s "lo,hi=10,90" "[sorted((lo,x,hi))[1] for x in range(100)]"
10000 loops, best of 3: 90.5 usec per loop

(生成元组并排序 - 抱歉,Gnibbler,这个是最慢的)

python -m timeit -s "lo,hi=10,90" "[lo if x <= lo else hi if x >= hi else x for x in range(100)]"
100000 loops, best of 3: 18.9 usec per loop

(最快的,没有函数调用,只有在 x > lo 的情况下才评估 x >= hi)

如果你把lo的值提高到测试范围的更高位置,就能看到这种快速结束的效果:

python -m timeit -s "lo,hi=80,90" "[lo if x <= lo else hi if x >= hi else x for x in range(100)]"
100000 loops, best of 3: 15.1 usec per loop

(如果你想在Python 2.x下重现这些,记得把 range 换成 xrange。)

撰写回答