# Finding if a given number is in a given range based on a flag

Question Description:

Given a number n, return True if n is in the range 1..10, inclusive. Unless outsideMode is True, in which case return True if the number is less or equal to 1, or greater or equal to 10.

in1to10(5, False) → **True**

in1to10(11, False) → **False**

in1to10(11, True) → **True**


The link to the problem is here.

Below is my first attempt. Please feel free to review it based on best practices, style and any other efficient solution.

def in1to10(n, outside_mode):
if(n>1 and n<10):
return not outside_mode
else:
return outside_mode or n is 10 or n is 1


Please feel free to review it based on best practices, style and any other efficient solution.

@mjolka already provided a more natural alternative implementation I completely agree with: following the logic precisely as in the problem statement is natural and easy to understand. I think the reason why it's easier to understand than yours has to do with the fact that the ranges being evaluated in the 2 distinct cases depending on the value of outside_mode have an overlap on the values 1 and 10. If the two ranges were complements of each other, things would be simpler.

As for style:

if(n>1 and n<10):
return not outside_mode
else:
return outside_mode or n is 10 or n is 1


The parentheses in the if condition are redundant. And PEP8 recommends to put spaces around operators, so this would be better:

if n > 1 and n < 10:


Even better is to use Python's kick-ass ... < ... < ... operator:

if 1 < n < 10:


Be careful with using is. In this example it works as expected, but if you try to use for non-primitive types, it might not give what you expect:

>>> [1, 2] is [1, 2]
False
>>> (1, 2) is (1, 2)
False


Unless there is a specific reason to use is, I think you should use ==:

return outside_mode or n == 10 or n == 1


The logic is confusing. A direct translation of the problem specification is possible, and clearer.

Let's deal with the first half of the problem:

Given a number $n$, return True if $n$ is in the range $1 ..10$, inclusive.

Then it's natural to write:

def in1to10(n):
return 1 <= n <= 10


Now we can deal with the second half:

def in1to10(n, outside_mode):
if outside_mode:
return n <= 1 or n >= 10
return 1 <= n <= 10

• Well you could do this but I tried to use python's verbose mode for high level translation, too many logical operators make it more confusing, don't you think? Oct 17 '14 at 5:46
• The logical operators in the original code: and, not, or, or = 4. In this answer: or = 1. So, not sure what you mean... Oct 17 '14 at 5:55
• I meant <=, >= mainly, where is =4 btw? :-s Oct 17 '14 at 5:59
• janos means that there are 4 logical operators in the original code. In mjolka's answer there are only 1 (or). Oct 17 '14 at 6:10
• sorry I meant relational operators, my bad!! Oct 17 '14 at 6:13

Questions like this generally involve working out how to understand boolean operations. There is a difference between that understanding, and making things readable, but, your solution is:

def in1to10(n, outside_mode):
if(n>1 and n<10):
return not outside_mode
else:
return outside_mode or n is 10 or n is 1


I don't find that to be particularly horrible to read, but I think it is missing the point of whatever lesson you are supposed to be learning.

I actually prefer the suggestion from @mjolka):

def in1to10(n, outside_mode):
if outside_mode:
return n <= 1 or n >= 10
return 1 <= n <= 10


because it makes the 'flag' the logical differentiator. If it was me, I would write it @mjolka's way

On the other hand, the exercise is probably trying to teach you that you can != two boolean values as an XOR operation (or alternatively use == as a NOT-XOR operation). Consider the following two boolean variables: old and working:

old != working is true when you're old and not working, or working and not old. It is false when you're old and working, or you're not old and not working. Since young people are supposed to be working, and old people are supposed to be retired, and assuming that people are happy in these states, then you could say:

happy = old != working


How does this relate to your problem?

Well, consider the following function:

def in1to10(n, outside_mode):
return n is 10 or n is 1 or (outside_mode != (1 < n < 10))


But, the line:

return n is 10 or n is 1 or (outside_mode != (1 < n < 10))


is probably the better way to do it all as a single boolean expression rather than the (more readable?) if-statement.

When I run that in this program:

#!/usr/bin/python

def in1to10(n, outside_mode):
return n is 10 or n is 1 or (outside_mode != (1 < n < 10))

for i in range(-5, 15):
print('input {:3d} inside {:5s}   outside {:5s}'
.format(i, str(in1to10(i, False)), str(in1to10(i, True))))


I get the output:

input  -5 inside False   outside True
input  -4 inside False   outside True
input  -3 inside False   outside True
input  -2 inside False   outside True
input  -1 inside False   outside True
input   0 inside False   outside True
input   1 inside True    outside True
input   2 inside True    outside False
input   3 inside True    outside False
input   4 inside True    outside False
input   5 inside True    outside False
input   6 inside True    outside False
input   7 inside True    outside False
input   8 inside True    outside False
input   9 inside True    outside False
input  10 inside True    outside True
input  11 inside False   outside True
input  12 inside False   outside True
input  13 inside False   outside True
input  14 inside False   outside True


Note: What I am trying to say is that even though the boolean logic XOR is what the exercise probably wants, I would still write it with an if-statement (like @mjolka), but you still need to understand how the boolean XOR would work.

## Solution

Python supports double-ended inequalities. To implement just the first part, write

def in1to10(n):
return 1 <= n <= 10


Adding support for outsideMode

def in1to10(n, outsideMode):
if outsideMode:
return not(1 < n < 10)
else:
return 1 <= n <= 10


Unfortunately, outsideMode isn't not(1 <= n <= 10), so you can't do anything clever with XOR, like

# Wrong!
def in1to10(n, outsideMode):
return outsideMode ^ (1 <= n <= 10)


(Well, you could, but the added complication is not worth it.)

## Style notes

In Python, it is conventional to omit parentheses for simple if conditions. It is also more common to use lower_case_with_underscores for parameter and local/instance variable names. See examples in PEP8.

CodingBat is inconsistent in the naming: it uses outsideMode in the question, and outside_mode in the text area.

It seems that your original code does not work correctly, as taking your code:

def in1to10(n, outside_mode):
if(n>1 and n<10):
return not outside_mode
else:
return outside_mode or n is 10 or n is 1


and calling it in this manner, with the expected output in the comment next to the func call:

print in1to10(-1, False)            # → **False**
print in1to10(-1, True)             # → **True**
print in1to10(1, False)             # → **True**
print in1to10(1, True)              # → **False**
print in1to10(10, False)            # → **True**
print in1to10(10, True)             # → **False**
print in1to10(5, False)             # → **True**
print in1to10(5, True)              # → **False**
print in1to10(11, False)            # → **False**
print in1to10(11, True)             # → **True**


produces these responses (output → expected_output):

False  → **False**
True   → **True**
True   → **True**
True   → **False**
True   → **True**
True   → **False**
True   → **True**
False  → **False**
False  → **False**
True   → **True**
Asdf   → **False**


Notice that your original answer does not catch nor raise an error when encountering a string val.

I've reworked your code to this:

def in1to10(n, outside_mode=False):
retval = True if outside_mode == False else False
return retval if 1 <= n <= 10 else not retval


which does the following:

1. It defaults outside_mode to False, so that we can omit it and only give it a number to check if its within the range
2. Checks if n is within a range elegantly
3. Uses the retval var as a flip switch boolean
4. Handles strings and outputs False if its a string
5. Correctly outputs the expected output

This is the output of my version of the func (using the same calls and expected output as above in the original call) (output → expected_output):

False  → **False**
True   → **True**
True   → **True**
False  → **False**
True   → **True**
False  → **False**
True   → **True**
False  → **False**
False  → **False**
True   → **True**
False  → **False**

• The specification makes it quite clear that the numbers 1 and 10 are in range in both modes. Oct 17 '14 at 7:24
• Good point...in my defense, this was written up at 2am :) Oct 17 '14 at 15:36
• hey take some rest.. Oct 19 '14 at 15:03