问题可能听起来很复杂,但实际上非常简单,但我在Python中找不到任何好的解决方案。
我的范围很像
("8X5000", "8X5099")
。此处X
可以是任意数字,因此我希望匹配属于某个范围(805000..805099
或815000..815099
或... 895000..895099
)的数字。
我该怎么做?
答案 0 :(得分:3)
@TimPietzcker的答案是正确的和Pythonic,但它提出了一些性能问题(可以说它更像Pythonic)。它创建一个搜索值的迭代器。我不希望Python能够优化搜索。
这应该表现得更好:
def IsInRange(n, r=("8X5000", "8X5099")):
(minr, maxr) = [[int(i) for i in l.split('X')] for l in r]
p = len(r[0]) - r[0].find('X')
nl = (n // 10**p, n % 10**(p-1))
fInRange = all([minr[i] <= nl[i] <= maxr[i] for i in range(2)])
return fInRange
函数内部的第二行是嵌套列表理解,因此可能有点难以阅读,但它设置了:
minr = [8, 5000]
maxr = [8, 5099]
当n = 595049时:
nl = (5, 5049)
代码只是将范围拆分为多个部分(转换为int时),将目标数字拆分为多个部分,然后范围检查部分。在范围说明符中处理多个X是不难的。
我刚刚使用timeit测试了相对性能:
def main():
t1 = timeit.timeit('MultiRange.in_range(985000)', setup='import MultiRange', number=10000)
t2 = timeit.timeit('MultiRange.IsInRange(985000)', setup='import MultiRange', number=10000)
print t1, t2
print float(t2)/float(t1), 1 - float(t2)/float(t1)
在我运行Python 2.7.2的32位Win 7机器上,我的解决方案几乎是@TimPietzcker的10倍(具体来说,它在12%的时间内运行)。当你增加范围的大小时,它只会变得更糟。当:
ranges=("8X5000", "8X5999")
性能提升50倍。即使是最小的范围,我的版本运行速度也要快4倍。
使用@PaulMcGuire建议的in_range
性能补丁,我的版本运行速度提高了3倍。
在@PaulMcGuire的评论的推动下,我继续将我们的功能重构为课程。这是我的:
class IsInRange5(object):
def __init__(self, r=("8X5000", "8X5099")):
((self.minr0, self.minr1), (self.maxr0, self.maxr1)) = [[int(i) for i in l.split('X')] for l in r]
pos = len(r[0]) - r[0].find('X')
self.basel = 10**(pos-1)
self.baseh = self.basel*10
self.ir = range(2)
def __contains__(self, n):
return self.minr0 <= n // self.baseh <= self.maxr0 and \
self.minr1 <= n % self.basel <= self.maxr1
这确实缩小了差距,但即使在预计算范围不变量(对于两者)之后,@ PaulMcGuire的时间也延长了50%。
答案 1 :(得分:1)
range = (80555,80888)
x = 80666
print range[0] < x < range[1]
也许你在寻找......
答案 2 :(得分:1)
Python 3的示例(在Python 2中,使用xrange
而不是range
):
def in_range(number, ranges=("8X5000", "8X5099")):
actual_ranges = ((int(ranges[0].replace("X", digit)),
int(ranges[1].replace("X", digit)) + 1)
for digit in "0123456789")
return any(number in range(*interval) for interval in actual_ranges)
结果:
>>> in_range(805001)
True
>>> in_range(895099)
True
>>> in_range(805100)
False
Paul McGuire建议对此进行改进(谢谢!):
def in_range(number, ranges=("8X5000", "8X5099")):
actual_ranges = ((int(ranges[0].replace("X", digit)),
int(ranges[1].replace("X", digit)))
for digit in "0123456789")
return any(minval <= number <= maxval for minval, maxval in actual_ranges)