TransWikia.com

Largest odd number

Code Review Asked by Neisy Sofía Vadori on January 17, 2021

Ask user to input 10 integers and then print the largest odd number that was entered. If no odd number was entered, print a message to that effect.

I’ve been trying to solve this problem with python and I think I’ve figured out a way that covers all the cases that are possible given the mathematical definition of an odd number. In order to be sure, I would like to check if my code is correct given your own criteria.

counter = 0
odd = []

while counter < 10:
    x = int(input("Enter a number: "))
    if abs(x)%2 != 0:
        odd.append(x)
    counter += 1

if len(odd) == 0:
    print("No odd number was entered")
else:
    print("The largest odd number is:", max(odd))

5 Answers

For your current program we can improve a couple things:

  1. Rename odd to odds (since it is a list).
  2. Use not odds instead of len(odds) == 0 (see How do I check if a list is empty? for a reason as to why this is preferred).
  3. Delete counter. Since we only use counter in the while condition, we can actually replace the whole while with for _ in range(10).
  4. Follow PEP 8. For example, using 4 spaces for each indentation level.

Factoring in all these changes, we get:

odds = []

for _ in range(10):
    x = int(input("Enter a number: "))
    if abs(x) % 2 != 0:
        odds.append(x)

if not odds:
    print("No odd number was entered")
else:
    print("The largest odd number is:", max(odds))

But we can also improve the efficiency of this program. Right now we keep track of all odd numbers, before choosing the max. This means that the space complexity is O(N). We can change this to O(1) by keeping track of the largest odd number like so:

max_odd = None

for _ in range(10):
    x = int(input("Enter a number: "))

    if abs(x) % 2 != 0:
        max_odd = x if max_odd is None else max(max_odd, x)

if max_odd is None:
    print("No odd number was entered")
else:
    print("The largest odd number is: ", max_odd)

Note that we use None to signify that no odd number has been entered so far, in which case upon an odd number being entered we set max_odd to x directly. Otherwise, we set max_odd to max(max_odd, x).

For this type of program you will not notice the increase in efficiency due to reducing the space complexity. But learning to recognize where these reductions are possible will allow you to see the same patterns in programs where it does matter.

There is finally one more thing you can do. If you want to allow the program to keep accumulating numbers in the event that a str is accidentally typed which cannot be parsed as a number (such as ""), we can use a try / except wrapped in a while like so:

while True:
    try:
        x = int(input("Enter a number: "))
        break
    except ValueError:
        continue

This would replace:

x = int(input("Enter a number: "))

in the original code. This would keep prompting the user to type a str that is parsable as an int until they do. Since this is all happening in the same iteration of the for, the count of numbers they get to type (10 in our case) would not be reduced.

Correct answer by Mario Ishac on January 17, 2021

The key point here: each step in the process does just one simple thing. You build programs that way -- one incremental, tightly defined step at a time. Don't mix everything in a jumble -- e.g. a loop where we interact with a user while also making conversions and calculations needed later.

def as_int(s):
    try:
        return int(s)
    except Exception:
        return 0

N = 3
MSG = 'Enter number: '

replies = [input(MSG) for _ in range(N)]  # Interact.
nums = [as_int(r) for r in replies]       # Convert.
odds = [n for n in nums if n % 2]         # Compute.

if odds:                                  # Report.
    print(max(odds))

Answered by FMc on January 17, 2021

I'll try to build on the last suggestion of the accepted answer.

while True:
    try:
        x = int(input("Enter a number: "))
        break
    except ValueError:
        continue

I definitely endorse this suggestion, it allows your program to handle invalid input gracefully instead of just crashing.

However, it creates an usability problem. The user who just typoed a letter into a number probably did not notice it. They'll think they got the intended number in, proceed with the next, and then get confused at the end, when they think they got all numbers in, but the computer is still asking for the next one.

Better to give them feedback:

while True:
    try:
        x = int(input("Enter a number: "))
        break
    except ValueError:
        print("Invalid number will be ignored.")
        continue

... or even better, print their typoed number back at them:

while True:
    try:
        inputString = input("Enter a number: ")
        x = int(inputString)
        break
    except ValueError:
        print("Invalid number will be ignored: {}".format(inputString))
        continue

I would also consider keeping the full list of valid numbers entered, not just odd ones, and printing them all back at the user before the result, to give them a last chance to spot typos. They can, after all, have mistyped a valid but unintended number. Note that this would increase memory usage, and some would consider it over-communication.

print("Numbers provided are: {}".format(all_valid_numbers_inputted))
if not odds:
    print("No odd number was entered")
else:
    print("The largest odd number is:", max(odds))

If you do this, the next step would be to get rid of the "odds" variable, and figure out the largest odd directly from the full list.

Answered by Emilio M Bumachar on January 17, 2021

May I ask what programming language did you practice before python?
I want to mention a one-liner for this:

max(l,key=lambda x:(x%2,x))

assuming you already have l somehow inputed, like

s='Enter a number: '
l=[int(input(s)) for i in range(10)]

How does the code work? It looks for maximum of key(x) for x in l and returns such x. Key here is the lambda function that returns tuple (1,x) for odd x and (0,x) for even x. Tuples are compared left to right, e.g. (1,x)>(0,y) for every x and y. So we are just saying "give me the maximum of l, assuming that an odd number is always larger than an even number".

So all program will look like

s='Enter a number: '
l=[int(input(s)) for i in range(10)]
m=max(l,key=lambda x:(x%2,x))
if m%2:
    print('The largest odd number is: %d'%m)
else: #the greatest is even, therefore no odd numbers
    print('No odd number was entered')

Short, nice and easy, as python.

But I agree that a try-except block around int(input()) form the accepted answer is useful, along with no pre-storing the entire list of odd values.

I only wanted to demonstrate the paradigm of functional programming in python, when you just tell python 'I want that done (e.g. a maximum value)' and it does it for you, you don't need to explain how should it do it.

Thanks for reading.

Answered by Alexey Burdin on January 17, 2021

Adding to the previous review:

  • When x is an integer, abs(x) % 2 is equivalent to x % 2 in Python. The output of the modulo operator % has the same sign as the second operand.
  • When running code outside a method / class, it is a good practice to put the code inside a main guard. See here for more explanation.

In Python 3.8, the code can be shortened using the assignment operator := together with max function.

if __name__ == "__main__":
    # Number generator
    num_gen = (o for _ in range(10) if (o := int(input("Enter a number: "))) % 2 != 0)
    max_odd = max(num_gen, default=None)
    if max_odd is None:
        print("No odd number was entered")
    else:
        print(f"The largest odd number is: {max_odd}")

Wrapping int(input("Enter a number: ")) into a function provides better readability:

def read_input() -> int:
    return int(input("Enter a number: "))

if __name__ == "__main__":
    num_gen = (o for _ in range(10) if (o := read_input()) % 2 != 0)
    max_odd = max(num_gen, default=None)
    if max_odd is None:
        print("No odd number was entered")
    else:
        print(f"The largest odd number is: {max_odd}")

Another variant that handles invalid user inputs is as follows:

def read_input() -> int:
    while True:
        try:
            return int(input("Enter a number: "))
        except ValueError:
            continue

if __name__ == "__main__":
    try:
        max_odd = max(o for _ in range(10) if (o := read_input()) % 2 != 0)
        print(f"The largest odd number is: {max_odd}")
    except ValueError:
        # Since read_input() no longer raises ValueError, the except
        # statement here only handles the cases where max() gets no inputs
        print("No odd number was entered")

Answered by GZ0 on January 17, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP