Как назначить целочисленное значение из корзины - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь найти 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

Но тогда мне нужно проверить нижнюю и верхнюю границы и равенство, т. Е. Если это первая итерация цикла, я должен проверить, является ли подчиненный (<), тогда следующий цикл, который я должен проверить на подчиненный и равный (<=) . </p>

Я ищу что-то вроде этого (Ruby):

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

# Pass bucket to a method

Мой вопрос: Есть ли питонический способ сделать это с переменными границами и значениями?

Ответы [ 3 ]

0 голосов
/ 22 января 2019

Если я вас правильно понял, для каждого «ведра» у вас есть интервал. Чтобы проверить, принадлежит ли значение некоторому интервалу, вы можете определить функцию:

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)
0 голосов
/ 22 января 2019

С модулем 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, если все условия выполнены. Основное различие между bucket и conditions заключается в том, что вы можете добавить условия, которые не касаются границ, например, значение должно быть парным:

>>> 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. Я использовал кортежи, поскольку списки не могут быть хешируемыми (и поэтому не могут использоваться в качестве ключей dict);
  2. next((x for x in xs if <test>), None) принимает первый элемент в xs, который проходит тест. Если ни один элемент не проходит тест, возвращается значение по умолчанию None;
  3. В более старых версиях Python (<3.7) у вас нет гарантии порядка тестов. Это важно, если у вас есть перекрывающиеся условия. </li>
  4. Это явно неоптимально, потому что вы проверяете, если value < 100, тогда если value >= 100 и т. Д.

Это действительно питон? Я не уверен. Взгляните на https://www.python.org/dev/peps/pep-0020/, чтобы составить свою идею.

0 голосов
/ 22 января 2019

Я думаю, что это довольно питон, но я не рекомендую это

>>> 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 является значением по умолчанию.

EDIT

Вы можете создать функцию, основанную на той же концепции, что и 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
...