【问题标题】:How to get rid of bunch of ifs如何摆脱一堆ifs
【发布时间】:2015-02-04 12:25:01
【问题描述】:

考虑这样的任务:

你开得太快了,警察拦住了你。编写代码来计算结果,编码为 int 值:0=无票,1=小票,2=大票。如果速度小于等于 60,则结果为 0。如果速度在 61 和 80 之间,则结果为 1。如果速度大于或等于 81,则结果为 2。

首先想到的是一堆ifs,比如:

def caught_speeding(speed):
  if speed > 80:
      return 2
  elif speed > 60:
      return 1          
  else:
      return 0

是否有办法以更少的行数达到相同的结果?

【问题讨论】:

  • 为什么需要更少的行?您现在拥有的内容清晰易读。
  • @MartijnPieters,感谢指点,更正了我的解决方案。

标签: python


【解决方案1】:
>>> from bisect import bisect_left
>>> bisect_left([60, 80], 50)
0
>>> bisect_left([60, 80], 60)
0
>>> bisect_left([60, 80], 70)
1
>>> bisect_left([60, 80], 80)
1
>>> bisect_left([60, 80], 90)
2

所以你可以拥有

def caught_speeding(speed):
    bisect_left([60, 80], speed)

【讨论】:

    【解决方案2】:

    解决问题的通用方法是使用binary search;您可以使用bisect module 实现一个:

    import bisect
    
    def caught_speeding(speed):
       tickets = [60, 80]
       return bisect.bisect_left(tickets, speed)
    

    bisect_left 函数以尽可能最有效的方式为您的速度找到插入点(它会查看每个列表的 一半 以查看您的速度应该适合,然后再减半,直到找到插入点)。对于高达 60 的速度,您将其插入位置 0,对于 61 和 80 之间的速度,您将其插入位置 1,其余的将添加到最后的位置 2:

    >>> import bisect
    >>> tickets = [60, 80]
    >>> bisect.bisect_left(tickets, 60)
    0
    >>> bisect.bisect_left(tickets, 61)
    1
    >>> bisect.bisect_left(tickets, 80)
    1
    >>> bisect.bisect_left(tickets, 81)
    2
    

    对于仅 3 种不同的票值,这确实有点矫枉过正。稍后返回您的代码时,您的 3 分支 if-elif-else 构造会更容易理解。

    【讨论】:

    • 谢谢,这就是为什么我问是否有更好的方法。我以前没有读过关于 bisect 的文章
    【解决方案3】:

    虽然没有使用bisect 快,因为它进行线性搜索,但以下对间隔或指定它们的顺序做出了一些假设(也没有关于正在比较的值的种类,可能是整数,浮点数、日期等):

    import sys
    
    def caught_speeding(speed, intervals):
        for i, interval in enumerate(intervals):
            if interval[0] <= speed <= interval[1]:
                return i
        return None  # wasn't in any interval
    
    speed_ranges = [[0, 60], [61, 80], [81, sys.maxint]]
    
    print(caught_speeding(45, speed_ranges))  # --> 0
    print(caught_speeding(65, speed_ranges))  # --> 1
    print(caught_speeding(90, speed_ranges))  # --> 2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-28
      • 2013-10-31
      • 2020-10-19
      • 2019-12-01
      • 2013-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多