Python 3 - 基于范围的分配

时间:2016-08-20 05:35:22

标签: python python-3.x range conditional

我有一本字典:

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"

这是经过调整的代码,可以解决问题。这是正确的方法吗?它似乎不是正确的解决方案,但我想不出正确的解决方案是什么(除了等效的间隔条件)。

2 个答案:

答案 0 :(得分: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

如果您需要快速检索并且愿意使用更多空间,您可以创建包含所有有效值的dict,以便检索 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

上述方法的可行性显然取决于您拥有多少有效值。

答案 1 :(得分: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以更易读的方式检查范围。