Python 3 - задание на основе диапазона

python python-3.x range conditional

97 просмотра

2 ответа

У меня есть словарь:

BATTERY_LEVEL_TRANSFORMS = {(75, 101): "High", (30, 75): "Medium", (0, 30): "Low"}

и я пытаюсь установить текстовый индикатор на основе значения батареи. Какой бы клавише она ни находилась в диапазоне, текст будет назначен соответствующим образом. Вот что у меня есть:

    for level_range, level_text in BATTERY_LEVEL_TRANSFORMS.items():
        if msg in range(*level_range):
            batt_level_str = level_text
            break
        else:
            batt_level_str = "Error"

Это скорректированный код, чтобы сделать проблему понятной. Это правильный способ сделать это? Это не кажется правильным решением, но я не могу думать о том, каким будет правильное решение (кроме условных эквивалентных интервалов).

Автор: linus72982 Источник Размещён: 08.11.2019 10:55

Ответы (2)


1 плюс

Решение

Я на самом деле думаю, что ваше решение не плохо. Вот мой вариант, чтобы сделать его немного более читабельным:

BATTERY_LEVELS = (
    (0, 30, 'Low'),
    (30, 75, 'Medium'),
    (75, 101, 'High'),
)


def get_level_text(level):
    for low, high, level_text in BATTERY_LEVELS:
        if low <= level <= high:
            return level_text
    return 'Error'

print(get_level_text(20))  # Low
print(get_level_text(40))  # Medium
print(get_level_text(80))  # High
print(get_level_text(120))  # Error

Вот изменения и их обоснование:

  1. Измените BATTERY_LEVEL_TRANSFORMSсловарь кортежей на текст, просто на кортеж с именем кортежей BATTERY_LEVELS. Поскольку эта структура не изменяется и кортежи неизменны, это выглядит как упрощение. Также нет необходимости иметь словарь, так как у нас просто есть куча связанных данных без четкого ключа.
  2. Измените msgна, levelтак как это кажется числовым значением.
  3. Теперь, когда у нас есть кортеж кортежей, измените цикл, чтобы иметь интуитивно понятные имена переменных, используя low, high, level_textдля хранения значений кортежей.
  4. Измените условие на, if low <= level <= highчтобы проверить диапазон более читабельным способом.
Автор: Karin Размещён: 20.08.2016 05:58

2 плюса

Одним из вариантов будет сохранение точек останова между уровнями и именами уровней в двух отсортированных списках и использование bisect.bisect_rightдля выполнения двоичного поиска по точкам останова. Преимущество этого подхода состоит в том, что извлечение уровня будет иметь сложность времени O (log n), хотя на самом деле не имеет значения, когда у вас есть только несколько уровней:

from bisect import bisect_right

LEVELS = [0, 30, 75, 101]
TEXTS = ['Low', 'Medium', 'High']

def get_level(num):
    index = bisect_right(LEVELS, num) - 1
    return TEXTS[index] if 0 <= index < len(TEXTS) else 'Error'

for x in [-1, 0, 29, 30, 74, 75, 100, 101]:
    print('{}: {}'.format(x, get_level(x)))

Выход:

-1: Error
0: Low
29: Low
30: Medium
74: Medium
75: High
100: High
101: Error

Если вам нужен быстрый поиск и вы хотите использовать больше места, вы можете создать подсказку, содержащую все допустимые значения, так что поиск будет иметь O (1) временную сложность:

BATTERY_LEVEL_TRANSFORMS = {(75, 101): "High", (30, 75): "Medium", (0, 30): "Low"}
LEVEL_MAP = {i: level
             for (lo, hi), level in sorted(BATTERY_LEVEL_TRANSFORMS.items())
             for i in range(lo, hi)}

def get_level(num):
    return LEVEL_MAP.get(num, 'Error')

for x in [-1, 0, 29, 30, 74, 75, 100, 101]:
    print('{}: {}'.format(x, get_level(x)))

Выход:

-1: Error
0: Low
29: Low
30: Medium
74: Medium
75: High
100: High
101: Error

Осуществимость вышеуказанного подхода, очевидно, зависит от того, сколько допустимых значений у вас есть.

Автор: niemmi Размещён: 20.08.2016 06:15
Вопросы из категории :
32x32