4
\$\begingroup\$

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
asked Oct 17, 2014 at 5:25
\$\endgroup\$

5 Answers 5

4
\$\begingroup\$

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
answered Oct 17, 2014 at 6:33
\$\endgroup\$
1
7
\$\begingroup\$

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
answered Oct 17, 2014 at 5:42
\$\endgroup\$
7
  • \$\begingroup\$ 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? \$\endgroup\$ Commented Oct 17, 2014 at 5:46
  • \$\begingroup\$ The logical operators in the original code: and, not, or, or = 4. In this answer: or = 1. So, not sure what you mean... \$\endgroup\$ Commented Oct 17, 2014 at 5:55
  • \$\begingroup\$ I meant <=, >= mainly, where is =4 btw? :-s \$\endgroup\$ Commented Oct 17, 2014 at 5:59
  • 2
    \$\begingroup\$ janos means that there are 4 logical operators in the original code. In mjolka's answer there are only 1 (or). \$\endgroup\$ Commented Oct 17, 2014 at 6:10
  • \$\begingroup\$ sorry I meant relational operators, my bad!! \$\endgroup\$ Commented Oct 17, 2014 at 6:13
2
\$\begingroup\$

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.

answered Oct 17, 2014 at 12:11
\$\endgroup\$
2
\$\begingroup\$

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.

answered Oct 18, 2014 at 17:34
\$\endgroup\$
0
\$\begingroup\$

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**
print in1to10("adsf", "Asdf") # False

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**
answered Oct 17, 2014 at 6:18
\$\endgroup\$
3
  • 3
    \$\begingroup\$ The specification makes it quite clear that the numbers 1 and 10 are in range in both modes. \$\endgroup\$ Commented Oct 17, 2014 at 7:24
  • \$\begingroup\$ Good point...in my defense, this was written up at 2am :) \$\endgroup\$ Commented Oct 17, 2014 at 15:36
  • \$\begingroup\$ hey take some rest.. \$\endgroup\$ Commented Oct 19, 2014 at 15:03

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.