質問は複雑に聞こえるかもしれませんが、実際には非常に単純ですが、Python で適切な解決策が見つかりません。
のような範囲があります
("8X5000", "8X5099")
。ここには任意の数字を指定できるため、範囲 (またはまたは ... ) のいずれかX
に該当する数字と一致させたいと考えています。805000..805099
815000..815099
895000..895099
これどうやってするの?
@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
関数内の2行目はネストされたリスト内包表記であるため、少し読みにくいかもしれませんが、次のように設定されます。
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)
Python2.7.2を実行している32ビットのWin7マシンでは、私のソリューションは@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%長くかかりました。
range = (80555,80888)
x = 80666
print range[0] < x < range[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)