【问题标题】:Python: Mapping from intervals to valuesPython:从间隔映射到值
【发布时间】:2010-11-15 00:06:18
【问题描述】:

我正在重构一个函数,给定一系列隐式定义区间的端点,检查区间中是否包含一个数字,然后返回一个对应的(不以任何可计算的方式相关)。 现在处理这项工作的代码是:

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

这在 IMO 中非常可怕,并且缺少间隔和返回值都是硬编码的。 当然可以使用任何数据结构。

【问题讨论】:

    标签: python range intervals


    【解决方案1】:
    import bisect
    bisect.bisect_left([100,300,500,800,1000], p)
    

    这里是文档:bisect

    【讨论】:

    • 确实令人印象深刻。超级干净,我相信也很快。如果确实需要非自然排序或其他东西作为回报,它也可以轻松扩展,例如字符串: import bisect n = bisect.bisect_left([100,300,500,800,1000], p) a=["absent","低”、“平均”、“高”、“非常高”、“极端”] a[n]
    • hmmm 但这不会返回“任意值”,而是返回索引。我如何让它返回任意值?我试过p = 10 x = bisect.bisect_left(OrderedDict({10: 'a', 11: 'b'}), p) print() ,但没用。
    【解决方案2】:
    def which_interval(endpoints, number):
        for n, endpoint in enumerate(endpoints):
            if number <= endpoint:
                return n
            previous = endpoint
        return n + 1
    

    将您的端点作为endpoints 中的列表传递,如下所示:

    which_interval([100, 300, 500, 800, 1000], 5)
    

    编辑:

    以上是线性搜索。 Glenn Maynard 的答案将具有更好的性能,因为它使用二等分算法。

    【讨论】:

    • 失去“以前的”雀跃;这是相当多余的。
    • 是的,你是对的,我猜原始代码“启发”了我使用它。顺便说一句,您对命令式的使用对某些人来说可能听起来有点生硬。
    • @Steef:您可能希望考虑一个谦虚的建议,您可能会在闲暇时修改您的答案,请注意您的答案仍然包含多余的代码行,并在时间满了,消费也一样。
    【解决方案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
    

    【讨论】:

    • 我比得票最多的那个更喜欢这个,因为它的形式更通用/非硬编码,而且更深入。
    【解决方案4】:

    另一种方式...

    def which(lst, p): 
        return len([1 for el in lst if p > el])
    
    lst = [100, 300, 500, 800, 1000]
    which(lst, 2)
    which(lst, 101)
    which(lst, 1001)
    

    【讨论】:

      【解决方案5】:

      你可以试试这个:

      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 中,会有更好的方法来做到这一点。

      【讨论】:

      • 不考虑p > 1000的情况!
      • 这就是为什么我指定:“你可以试试这个”
      • 最后一句话具有讽刺意味,考虑到 python 哲学最好只有一种明显的方式来做某事。
      • BUG:如果 p 大于最后一个端点,它会产生 None。
      【解决方案6】:

      尝试以下方式:

      d = {(None,100): 0, 
          (100,200): 1,
          ...
          (1000, None): 5}
      value = 300 # example value
      for k,v in d.items():
          if (k[0] is None or value > k[0]) and (k[1] is None or value <= k[1]):
              return v
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-19
        • 1970-01-01
        • 2014-11-29
        • 2021-12-31
        • 2023-03-04
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        相关资源
        最近更新 更多