简体   繁体   English

检查一个数字属于哪个特定范围(在许多范围内)的最pythonic方法是什么?

[英]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)

Edit 1编辑 1

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM