如何从箱中分配整数值

时间:2019-01-22 06:38:52

标签: python python-3.x binning

我试图找到一种pythonic的方法来根据变量所在的位置来分配数值。即:

variable = 23
if variable < -100:
    return_value = -15
elif variable <= -5:
    return_value = -4
elif variable <= 5:
    return_value = 18
else:
    return_value = 88

我当然可以创建一个包含存储桶/值的列表,并在找到正确的值时进行遍历并返回:

bucket_values = [(-100, -15), (-5, -4), (5, 18)]
default = 88
variable = 100
for lower_bound, value in bucket_values:
    if variable < lower_bound:
        return_value = value
        break
else:
    return_value = default

但是然后我需要检查上下限和相等性,即如果是循环的第一次迭代,则必须检查下级(<),然后下一个循环必须检查下级和等于(<=)

我正在寻找这样的东西(Ruby):

buckets = [
[:<, -90, -57], 
[:<=, 5, -10], 
[:<=, 10, 3], 
[:>, 60, 40]] 

# Pass bucket to a method

我的问题是: 是否存在使用可变范围和值的Python方法?

3 个答案:

答案 0 :(得分:1)

使用模块operator非常简单。这是一个示例:

>>> import operator
>>> bucket = (operator.ge, -100, operator.le, -5)
>>> def in_bucket(value, bucket): return bucket[0](value, bucket[1]) and bucket[2](value, bucket[3])
...
>>> in_bucket(-101, bucket)
False
>>> in_bucket(-100, bucket)
True
>>> in_bucket(-5, bucket)
True
>>> in_bucket(-4, bucket)
False

但是,通过定义一个更通用的结构,您可以做得更好:

>>> conditions = ((operator.ge, -100), (operator.le, -5))
>>> def match_conditions(value, conditions): return all(c[0](value, c[1]) for c in conditions)
...
>>> match_conditions(-101, conditions)
False
>>> match_conditions(-100, conditions)
True
>>> match_conditions(-5, conditions)
True
>>> match_conditions(-4, conditions)
False

如果满足所有条件,则all运算符将返回true。 bucketconditions之间的主要区别在于,您可以添加不涉及边界的条件,例如,值必须成对:

>>> conditions = ((operator.ge, -100), (operator.le, -5), (lambda v, _: v%2==0, None))
>>> match_conditions(-7, conditions)
False
>>> match_conditions(-6, conditions)
True
>>> match_conditions(-5, conditions)    
False

现在,您可以使用字典来总结您的情况(您给出的第一个示例):

>>> value_by_conditions = { 
... ((operator.lt, -100),): -15,
... ((operator.ge, -100), (operator.le, -5)): -4,
... ((operator.gt, -5), (operator.le, 5)): 18,
... ((operator.gt, 5),): 88,
... }
>>> next((v for cs, v in value_by_conditions.items() if match_conditions(23, cs)), None)
88
>>> next((v for cs, v in value_by_conditions.items() if match_conditions(-101, cs)), None)
-15
>>> next((v for cs, v in value_by_conditions.items() if match_conditions(-100, cs)), None)
-4

注意:

  1. 我使用元组,因为列表不可散列(因此不能用作字典键);
  2. next((x for x in xs if <test>), None)采用xs中通过测试的第一个元素。如果没有任何元素通过测试,它将返回默认值None;
  3. 在旧版本的Python(<3.7)中,您无法保证测试的顺序。如果条件重叠,这很重要。
  4. 这显然不是最佳选择,因为您测试的是value < 100,然后是value >= 100,等等。

这真的是pythonic吗?我不确定。看看https://www.python.org/dev/peps/pep-0020/来提出自己的想法。

答案 1 :(得分:0)

我认为这是非常pythonic的,但是我不推荐

>>> variable = 23
>>> return_value = -5 if variable<-100 else -4  if variable<=-4 else 18 if variable<= 5  else 88
>>> print(return_value)
88

请注意,88是默认值。

编辑

您可以创建一个基于与上面显示的if... else相同的概念的函数。该功能将是这样的:

def pythonic(variable, bucket_values, default):
    for k,v in bucket_values:
        return_value = v if variable<k else "---"
        if return_value != "---":
            return return_value
    return default

您可以像这样使用它:

>>> variable = 23
>>> bucket_values = [(-100, -15), (-5, -4), (5, 18)]
>>> print(pythonic(variable, bucket_values, 88))
88

>>> variable = 1
>>> print(pythonic(variable, bucket_values, 88))
18

答案 2 :(得分:0)

如果我对您的理解很好,那么每个“桶”都有一个间隔。要检查值是否属于某个间隔,可以定义一个函数:

def check_value(value, interval):
    if value in range(interval[0], interval[1]+1):
        print('Value ', value)
        print('Interval ', interval)
    else:
        pass

现在只需遍历间隔列表以查找值所属位置:

for interval in list_of_intervals:
    check_value(value, interval)