我有一本字典:
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"
这是经过调整的代码,可以解决问题。这是正确的方法吗?它似乎不是正确的解决方案,但我想不出正确的解决方案是什么(除了等效的间隔条件)。
答案 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
以下是它们背后的变化和推理:
BATTERY_LEVEL_TRANSFORMS
(一个元组到文本的字典)更改为一个名为BATTERY_LEVELS
的元组元组。由于这种结构没有变化,元组是不可变的,所以它似乎是一种简化。由于我们只有大量没有明确密钥的关联数据,因此也不需要字典。msg
更改为level
,因为它似乎是一个数值。low, high, level_text
来存储元组值来更改循环以获得直观的变量名。if low <= level <= high
以更易读的方式检查范围。