Существует ли Pythonic способ обработки такого отображения диапазона

#python

#python

Вопрос:

Можно ли сделать это более питоническим, пожалуйста?

 if joyx > 50:
   joyx = 100
elif joyx < -50:
   joyx = -100
else:
   joyx = 0
  

Ответ №1:

Вы можете написать его с помощью math.copysign abs функций and:

 In [30]: from math import copysign

In [31]: joyx = copysign(100, joyx) if abs(joyx) > 50 else 0
  

Пример:

 In [32]: joyx = lambda x: copysign(100, x) if abs(x) > 50 else 0

In [33]: joyx(51), joyx(-51), joyx(50), joyx(-50), joyx(0)
Out[33]: (100.0, -100.0, 0, 0, 0)
  

Комментарии:

1. Я думаю, что это более элегантный способ сделать это, но оригинал достаточно понятен.

2. Приятно 🙂 У меня уже загружена математика (это прога в 2000 строк!) Не знал о copysign — это будет очень полезно 🙂

Ответ №2:

На мой взгляд, то, что у вас есть, совершенно Pythonic.

Поскольку вы используете сравнения меньше и больше, мы не можем улучшить это, используя словарь или любой другой трюк, который я могу придумать.

Я думаю, вы могли бы разложить это на функцию и просто вызвать функцию:

 def clean_up_joystick(x, y, xbound, ybound, on_value):
    if x > xbound:
        x = on_value
    elif x < -xbound:
        x = -on_value
    else:
        x = 0
    if y > ybound:
        y = on_value
    elif y < -ybound:
        y = -on_value
    else:
        y = 0
    return (x, y)
  

Для реальной программы я предлагаю вам создать класс, который управляет джойстиком, и инициализировать класс со значениями границ, которые вы хотите использовать с любым конкретным джойстиком.

Может быть, что-то вроде этого:

 class Joystick(object):
    def __init__(self,
            x_low=-50, x_high=50,
            y_low=-50, y_high=50,
            on_value=100):
        self.x_low = x_low
        self.x_high = x_high
        self.y_low = y_low
        self.y_high = y_high
        self.on_value = on_value

    def read(self):
        # do something here that reads the joystick value
        # joystick value saved in x, y variables
        x, y = 0,0  # dummy init for example

        if x > self.x_high:
            x = self.on_value
        elif x < -self.x_low:
            x = -self.on_value
        else:
            x = 0
        if y > self.x_high:
            y = self.on_value
        elif y < self.x_low:
            y = -self.on_value
        else:
            y = 0
        return (x, y)

j = Joystick()
x, y = j.read()
  

Затем в вашей реальной программе вы просто используете j.read() для чтения джойстик и очистки входных данных. Если вам нужно изменить способ его работы, у вас есть одно место (класс). Просто убедитесь, что у вас есть разные экземпляры класса для каждого фактического джойстика, чтобы вы могли очищать разные джойстики, если у вас разные.

Комментарии:

1. 🙂 Я думаю, вы знаете, что я имел в виду 🙂 например, используйте функцию Python, чтобы сделать ее короче / усложненной. Как вы говорите — старый способ, который я изучил в BBC Basic, по-прежнему неплохой способ ведения дел 🙂

Ответ №3:

Возможно, вы находите это более pythonic:

 def get(joyx):
   joyx_min = -200
   joyx_max = 200
   from collections import namedtuple
   wheel_section = namedtuple("wheel_section", "min, max, output_value")
   roulette_wheel = [ wheel_section(joyx_min, -50, -100),  wheel_section(-50,51,0), wheel_section(51, joyx_max,100) ]
   for section in roulette_wheel:
     if  section.min <= joyx <  section.max:
       return section.output_value
   return 255
  

ваш код представляет собой очень упрощенную версию алгоритма колеса рулетки.
Я не уверен, что вам действительно следует создавать его полномасштабную версию.

Обновить

Значительно более короткая и красивая версия, использующая алгоритм с нижней границей:

 from bisect import bisect_left

# an intentionally larger: maps also 50 and -50 for demonstrational purposes.
data = { -200 : -100, -100 : -50, -50 : 0, 50 : 50, 220 : 100 }
keys = list(data.keys())


print data[  keys[ bisect_left(keys, -79)  ]  ] # prints -100
print data[  keys[ bisect_left(keys,  15)  ]  ] # prints 0
print data[  keys[ bisect_left(keys,  67)  ]  ] # prints 50
print data[  keys[ bisect_left(keys,  250) ]  ] # prints 100
  

Комментарии:

1. Нравится, но на самом деле ищет один лайнер (если он существовал) — ta 🙂

2. @SimpleSi Это адаптация колеса рулетки из генетических алгоритмов. Такие вещи в основном написаны на Java / C . это в основном полезно, если у вас больше значений, чем 3 (т. Е. Если вы хотите преобразовать диапазон с плавающей запятой в 10 различных целых значений). вы также можете выполнить двоичный поиск (наименьшее значение, превышающее пороговое значение) и сопоставить найденный индекс с набором дискретных значений. Я мог бы поместить это в (довольно нечитаемый) лямбда-выражение.