[英]What's the most pythonic way to check to what particular range (out of many) a number belongs?
I know I can check if a number X belongs to a particular range (out of Y consecutive ranges) by using concatenated if a<X<b elif b<X<C else...
but is there a more concise, pythonic way to do so?我知道我可以通过使用 concatenated if a<X<b elif b<X<C else...
来检查数字 X 是否属于特定范围(在 Y 个连续范围之外),但是是否有更简洁的 Pythonic 方式这样做?
There is several way, this one seems not so bad:有几种方法,这个似乎还不错:
def in_range(number : int, arange : range) -> bool:
return number in arange
ranges = [range(6), range(4, 14), range(10, 20), range(12, 34)]
results = list(filter(lambda arange : in_range(5, arange), ranges))
print(results)
[range(0, 6), range(4, 14)] [范围(0, 6), 范围(4, 14)]
You can simplify it like this.你可以像这样简化它。
def in_range(number : int, ranges : List[range]) -> List[range]:
return [arange for arange in ranges if number in arange]
ranges = [range(6), range(4, 14), range(10, 20), range(12, 34)]
print(in_range(6, ranges))
[range(0, 6), range(4, 14)] [范围(0, 6), 范围(4, 14)]
You may want to know it on the fly.您可能想即时了解它。
def in_range(number : int, start : int, stop : int) -> bool:
return number in range(start,stop)
You can also used any
or want to test it for float, in this case look at @chepner comment.您也可以使用any
或想要测试它的浮动,在这种情况下查看@chepner评论。
Use any
:使用any
:
x = 57
ranges = [range(10), range(15,27), range(38,42), range(49, 63), range(70, 95)]
if any(x in range for range in ranges):
...
If you can't use range
(because you are testing against an interval with non-integer end points), store the interval as a tuple.如果您不能使用range
(因为您正在测试具有非整数端点的区间),请将区间存储为元组。
ranges = [(1.5, 3.7), ...]
if any(t1 < x < t2 for t1, t2 in ranges):
If your consecutive ranges are dense (meaning there are no gaps in between), I would do如果您的连续范围很密集(意味着两者之间没有间隙),我会这样做
def get_range(boundaries, x):
for a, b in zip(boundaries, boundaries[1:]):
if a < x < b:
return a, b
# Test example
boundaries = [0, 5, 10, 15, 20]
x = 13
a, b = get_range(boundaries, x)
print(a, b) # 10 15
Note that the exact boundaries are not included in any of the ranges.请注意,确切的边界不包括在任何范围内。 Ie get_range(boundaries, 10)
does not find any range.即get_range(boundaries, 10)
没有找到任何范围。 To fix this, replace a < x < b
with eg a <= x < b
.要解决此问题,请将a < x < b
替换为例如a <= x < b
。
The above is great if you have a lot of ranges, where a hard-coded if
- elif
chain would be impractical.如果您有很多范围,那么上面的内容非常好,而硬编码的if
- elif
链将是不切实际的。 That said, if you have millions of ranges, you might want to be a bit more clever, like implementing a binary search.也就是说,如果你有数百万个范围,你可能想要更聪明一点,比如实现二进制搜索。
If you are looking to implement the equivalent of a switch statement (there isn't one in Python), you could define a utility function to make the code more concise and readable (ie avoiding repetitions):如果您希望实现等效的 switch 语句(Python 中没有),您可以定义一个实用程序 function 以使代码更简洁和可读(即避免重复):
def switch(value):
def inRange(a,b):
return a <= value and value < b
return inRange
number = 25
case = switch(number)
if case(10,20): print("small")
elif case(20,50): print("medium")
elif case(50,90): print("large")
else: print("huge")
you could also use this with ternary operators:您也可以将其与三元运算符一起使用:
inRange = switch(number)
size = "small" if inRange(10,20) else \
"medium" if inRange(20,50) else \
"large" if inRange(50,90) else \
"huge"
print(size)
If your ranges are consecutive, you could avoid repeating the upper boundaries using a bisecting search (which would give better performance for large lists of ranges):如果您的范围是连续的,您可以避免使用二等分搜索重复上边界(这将为大型范围列表提供更好的性能):
ranges = [10,20,50,90]
sizes = ["small","medium","large","huge"]
from bisect import bisect_right
size = sizes[bisect_right(ranges,number)-1]
print(size)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.