632

How do I determine whether a given integer is between two other integers (e.g. greater than/equal to 10000 and less than/equal to 30000)?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Average kid
  • 6,885
  • 6
  • 21
  • 17
  • 30
    Check your boolean operators, of course a number will be greater than 10000 if it's greater than 30000. Look at the little details and you will catch far more mistakes. – Kaili Sep 17 '13 at 14:41
  • 2
    Comparisons can be chained https://docs.python.org/2/reference/expressions.html#comparisons – theBuzzyCoder Aug 18 '17 at 06:52
  • 18
    Pls change >= 30000 to <= 30000 – Badiboy Sep 17 '18 at 21:07
  • 2
    The last edit made on this question is just putting "the solution" into the problem code. (makes the question somewhat invalid, defeats the purpose of this post I think.) – Caleb Dec 09 '20 at 20:35
  • The question clearly refers to the syntax of such comparison and has nothing to do with the number >= 30000 blunder. The edit was fine. – drakorg Jul 24 '21 at 04:37
  • @drakorg originally OP seems to have been asking because the typo in the code was causing wrong results. That should ordinarily have gotten the question closed, but there was a valid how-to question behind the wrong code. I removed the code from the question because it does not help understand the requirement, and because debugging a typo does not add value to Stack Overflow answers. – Karl Knechtel Mar 08 '23 at 15:51

16 Answers16

1516
if 10000 <= number <= 30000:
    pass

For details, see the docs.

Grilse
  • 3,491
  • 2
  • 28
  • 35
Paolo Moretti
  • 54,162
  • 23
  • 101
  • 92
  • 262
    Python is so nice :). And to be redundant: this is called "interval comparison." – Matt Montag Feb 11 '14 at 07:12
  • What is the speed difference between this and `if number in range(10000, 30001)` as suggested by other solution? Additionally, is it faster or slower when using `set` instead of `range`? – mc9 Aug 12 '15 at 00:37
  • 26
    @MikeC With the interval comparison `number` is first compared against `10000`. If it's less than `10000` the expression is immediately short-circuited and the second comparison is not checked. The complexity is `O(1)`. `in range(0, n)` instead generates the entire sequence of numbers and then iterates through it. The complexity is `O(n)`. The complexity of `in set(range(0, n))` is still `O(n)` because building a set has a time complexity of `O(n)` https://www.ics.uci.edu/~pattis/ICS-33/lectures/complexitypython.txt – Paolo Moretti Aug 12 '15 at 12:16
  • 10
    @MikeC Try to run in your shell: `> python -m timeit '10000 <= 10 <= 30000'` `> python -m timeit '10 in range(10000, 30001)'` `> python -m timeit '10 in set(range(10000, 30001))'` – Paolo Moretti Aug 12 '15 at 12:20
  • @SungWonCho, make sure to use `xrange` instead of `range` if you are testing on Python2 – John La Rooy Mar 09 '16 at 00:12
  • 7
    looks like in python3.5.2, range is ~10x slower than the if statement, with speed constant in regard to range check value...thus most likely difference due to function overhead. – amohr Nov 10 '16 at 00:21
  • @SungCho not only ```if number in range(10000, 30001)``` is slow, it'll eat up a lot of unnecessary memory. it'll create all those numbers in a list and make a linear search, range is meant for loops where the index is needed. – Ian Elvister Mar 03 '21 at 21:37
  • 1
    @IanElvister That's incorrect. `range` no longer creates a list in Python 3. See [Why is `10**15 in range(10**15+1)` so fast in Python 3?](/q/30081275/4518341) – wjandrea Sep 17 '22 at 20:29
  • Is there a way to add numbers with leading 0 in range , For ex: if number in range(00001,02021). I am getting the following error: SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers – Revanth Nov 08 '22 at 11:47
129
>>> r = range(1, 4)
>>> 1 in r
True
>>> 2 in r
True
>>> 3 in r
True
>>> 4 in r
False
>>> 5 in r
False
>>> 0 in r
False
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Bohdan
  • 16,531
  • 16
  • 74
  • 68
  • 4
    Wow I always thought `range` (or `xrange` in python2) returns a generator thus you cannot repeatedly test on it. – yegle Mar 03 '14 at 16:44
  • If the test range is huge (e.g. `range(1000000000)`), using `xrange` in python2 is pretty slow. But `range` in python3 doesn't suffer from this problem. – yegle Mar 03 '14 at 19:02
  • @yegle range (in python3) does not return an iterator, it returns a range object. range objects can be iterated more than once. – compie Jun 17 '14 at 11:55
  • 37
    Its important to so keep in mind that `4 in range(1,4)` is False. So better use the `1 >= r <= 4` as it avoids possible errors by newcomers – tripplet Jun 26 '14 at 08:01
  • 72
    `1.5 in r` gives `False`, even in 3.4. This answer is only good for integers. – jpmc26 Jan 05 '16 at 17:49
  • 1
    @jpmc26, good point. On the other hand you can specify a step size, so `range(1, n, 2)` lets you test for odd numbers. – John La Rooy Mar 09 '16 at 00:15
  • 13
    @tripplet, you made the same error as the OP!, It should be `1 <= r <= 4` – John La Rooy Mar 09 '16 at 00:16
  • `timeit i=100; i in xrange(1000) 1000000 loops, best of 3: 1.17 µs per loop In [16]: timeit i=100; 1 <=i<=1000 10000000 loops, best of 3: 39.2 ns per loop ` Plus the bigger i the longer it works . – Sergey Sep 28 '17 at 12:22
  • 10
    (1.) bad performance (as others have pointed out this syntax **looks good** but can take a long time to execute because it is O(n) operations vs the `if a <= x <= b`...) (2.) doesn't work for `float` types (3.) the range test is not-inclusive... so many developers may introduce bugs because they expect inclusive range – Trevor Boyd Smith Nov 03 '17 at 16:05
  • `x = 12000 RANGE_MIN = 10000 RANGE_MAX = 30000 if x == np.clip(x, RANGE_MIN, RANGE_MAX): print("x is OK")` – Enrique Pérez Herrero Dec 07 '20 at 08:56
  • @TrevorBoydSmith, I would say `x in range(...)` is not actually exhausting the range iterator according to this CPython implementation (https://github.com/python/cpython/blob/dc31334ab1b43225b65358fa361b46c22918b400/Objects/rangeobject.c#L383) – zhouhy Apr 25 '22 at 09:12
70

Use if number >= 10000 and number <= 30000:. Alternately, Python has a shorthand for this sort of thing, if 10000 <= number <= 30000:.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Silas Ray
  • 25,682
  • 5
  • 48
  • 63
  • 13
    ... *this sort of thing* is typically called [*chained comparison*](https://docs.python.org/3/reference/expressions.html#comparisons). – Wolf Oct 30 '19 at 14:57
38

To check that the number is in the range 10000 - 30000, use the Python interval comparison:

if 10000 <= number <= 30000:
    print ("you have to pay 5% taxes")

This Python feature is further described in the Python documentation.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Carl Ekerot
  • 2,078
  • 1
  • 16
  • 10
27

There are two ways to compare three integers and check whether b is between a and c:

if a < b < c:
    pass

and

if a < b and b < c:
    pass

The first one looks like more readable, but the second one runs faster.

Let's compare using dis.dis:

>>> dis.dis('a < b and b < c')
  1           0 LOAD_NAME                0 (a)
              2 LOAD_NAME                1 (b)
              4 COMPARE_OP               0 (<)
              6 JUMP_IF_FALSE_OR_POP    14
              8 LOAD_NAME                1 (b)
             10 LOAD_NAME                2 (c)
             12 COMPARE_OP               0 (<)
        >>   14 RETURN_VALUE
>>> dis.dis('a < b < c')
  1           0 LOAD_NAME                0 (a)
              2 LOAD_NAME                1 (b)
              4 DUP_TOP
              6 ROT_THREE
              8 COMPARE_OP               0 (<)
             10 JUMP_IF_FALSE_OR_POP    18
             12 LOAD_NAME                2 (c)
             14 COMPARE_OP               0 (<)
             16 RETURN_VALUE
        >>   18 ROT_TWO
             20 POP_TOP
             22 RETURN_VALUE
>>>

and using timeit:

~$ python3 -m timeit "1 < 2 and 2 < 3"
10000000 loops, best of 3: 0.0366 usec per loop

~$ python3 -m timeit "1 < 2 < 3"
10000000 loops, best of 3: 0.0396 usec per loop

also, you may use range, as suggested before, however it is much more slower.

Tiago Martins Peres
  • 14,289
  • 18
  • 86
  • 145
a_bridges
  • 386
  • 4
  • 11
14
if number >= 10000 and number <= 30000:
    print ("you have to pay 5% taxes")
Sandro Munda
  • 39,921
  • 24
  • 98
  • 123
14

Define the range between the numbers:

r = range(1,10)

Then use it:

if num in r:
    print("All right!")
joandiar91
  • 149
  • 1
  • 3
  • 4
    `range` doesn't count the last value **10** in your case . `range(1,11)` is correct, if you need to compare between 1 and 10 – Ikbel Apr 18 '19 at 09:07
11

Python lets you just write what you mean in words:

if number in xrange(10000, 30001): # ok you have to remember 30000 + 1 here :)

In Python3, use range instead of xrange.

edit: People seem to be more concerned with microbench marks and how cool chaining operations. My answer is about defensive (less attack surface for bugs) programming.

As a result of a claim in the comments, I've added the micro benchmark here for Python3.5.2

$ python3.5 -m timeit "5 in range(10000, 30000)"
1000000 loops, best of 3: 0.266 usec per loop
$ python3.5 -m timeit "10000 <= 5 < 30000"
10000000 loops, best of 3: 0.0327 usec per loop

If you are worried about performance, you could compute the range once

$ python3.5 -m timeit -s "R=range(10000, 30000)" "5 in R"
10000000 loops, best of 3: 0.0551 usec per loop
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • 2
    xrange is deprecated in Python 3, unfortunately. – apraetor Mar 02 '16 at 15:44
  • 1
    @apraetor, yes use `range(10000, 30001)` in Python3. It doesn't create a list – John La Rooy Mar 02 '16 at 19:38
  • 1
    your solution will iterate over 20 thousand integers. using <= and <= is much more efficient. – JBGreen Mar 08 '16 at 15:53
  • 4
    @JBChouinard, you are absolutely incorrect. `xrange` in Python2, or `range` in Python3 have membership tests. Try it yourself if you don't believe. `<=` is only more efficient because it doesn't create a range object. Both ways as O(1). The point is the OP _was_ **trying to do it your way and ended up with a bug**. Fast code that is wrong is worse. – John La Rooy Mar 08 '16 at 18:05
  • 2
    on an i5, (i)python 3.5: %timeit 5 in range(10000, 30000) 1000 loops, best of 3: 451 µs per loop. %timeit 10000 <= 5 <= 30000 10000000 loops, best of 3: 59.4 ns per loop. that's a factor of over 7000 – tback Nov 10 '16 at 10:03
  • 1
    @tback, If there were a chance it was 7000 times slower, I would not have suggested it. Perhaps you could try running the test again. – John La Rooy Nov 11 '16 at 02:36
  • @tback I reran your tests and got ```timeit 5 in range(10000, 30000)``` ```428 ns ± 19.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)``` and ```%timeit 10000 <= 5 <= 30000``` ```71.6 ns ± 4.88 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)``` on an i7 python 3.6.3 so only 6x slower. – Techniquab Oct 12 '20 at 21:03
11

Below are few possible ways, ordered from best to worse performance (i.e first one will perform best)

     # Old school check
     if 10000 <= b and b <=30000:
        print ("you have to pay 5% taxes")
     # Python range check
     if 10000 <= number <= 30000:
        print ("you have to pay 5% taxes")
     # As suggested by others but only works for integers and is slow
     if number in range(10000,30001):
        print ("you have to pay 5% taxes")
tzot
  • 92,761
  • 29
  • 141
  • 204
Vikrant Gupta
  • 217
  • 2
  • 7
8

While 10 <= number <= 20 works in Python, I find this notation using range() more readable:

if number in range(10, 21):
    print("number is between 10 (inclusive) and 21 (exclusive)")
else:
    print("outside of range!")

Keep in mind that the 2nd, upper bound parameter is not included in the range set as can be verified with:

>>> list(range(10, 21))
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

However prefer the range() approach only if it's not running on some performance critical path. A single call is still fast enough for most requirements, but if run 10,000,000 times, we clearly notice nearly 3 times slower performance compared to a <= x < b:

> { time python3 -c "for i in range(10000000): x = 50 in range(1, 100)"; } 2>&1 | sed -n 's/^.*cpu \(.*\) total$/\1/p'
1.848

> { time python3 -c "for i in range(10000000): x = 1 <= 50 < 100"; } 2>&1 | sed -n 's/^.*cpu \(.*\) total$/\1/p'
0.630
Lars Blumberg
  • 19,326
  • 11
  • 90
  • 127
  • 3
    Note that `10 <= 10.5 <= 20` is True while `10.5 in range(10, 21)` is False; depending on the situation, that may or may not be what you intend – Jiří Baum Oct 27 '21 at 09:43
  • While this is true for floats, OP precisely asked about integer comparison. – Lars Blumberg Oct 27 '21 at 13:55
  • Ah, so they have; in that case, the two expressions are indeed equivalent – Jiří Baum Oct 27 '21 at 22:17
  • If the bounds are pre-defined, there is no need to construct a new `range` object each time. Still slower than the `<= <=` construct, but it takes only 1.5× the time on my machine, not 3×. – tzot May 04 '23 at 08:50
5

Suppose there are 3 non-negative integers: a, b, and c. Mathematically speaking, if we want to determine if c is between a and b, inclusively, one can use this formula:

(c - a) * (b - c) >= 0

or in Python:

> print((c - a) * (b - c) >= 0)
True
2

I'm adding a solution that nobody mentioned yet, using Interval class from sympy library:

from sympy import Interval

lower_value, higher_value = 10000, 30000
number = 20000

 # to decide whether your interval shhould be open or closed use left_open and right_open 
interval = Interval(lower_value, higher_value, left_open=False, right_open=False)
if interval.contains(number):
    print("you have to pay 5% taxes")
Tom
  • 496
  • 8
  • 16
0

You want the output to print the given statement if and only if the number falls between 10,000 and 30,000.

Code should be;

if number >= 10000 and number <= 30000:
    print("you have to pay 5% taxes")
Jaideep Shekhar
  • 808
  • 2
  • 7
  • 21
0

You used >=30000, so if number is 45000 it will go into the loop, but we need it to be more than 10000 but less than 30000. Changing it to <=30000 will do it!

Hassan
  • 9
  • 1
-1

Try this simple function; it checks if A is between B and C (B and C may not be in the right order):

def isBetween(A, B, C):
    Mi = min(B, C)
    Ma = max(B, C)
    return Mi <= A <= Ma

so isBetween(2, 10, -1) is the same as isBetween(2, -1, 10).

Ivan
  • 34,531
  • 8
  • 55
  • 100
-6

The condition should be,

if number == 10000 and number <= 30000:
     print("5% tax payable")

reason for using number == 10000 is that if number's value is 50000 and if we use number >= 10000 the condition will pass, which is not what you want.

Mert Köklü
  • 2,183
  • 2
  • 16
  • 20
Sadaf
  • 9
  • 3
  • This will fail for 10001, for example, though. He wants numbers between 10000 and 30000. Your condition will only work for number == 10000. – guerreiro May 01 '20 at 20:45
  • This will fail for the user's requirement. This is not an appropriate solution. – anjandash Aug 10 '20 at 15:42