12
\$\begingroup\$
def greatest(a,b):
    if a>b:
        return a
    return b
def odd_check(a):
    return not(a%2 == 0)
def go(x,y,z):
    a = odd_check(x)
    b = odd_check(y)
    c = odd_check(z)
    if a and b and not c:
        print greatest(x,y)
    elif a and not b and c:
        print greatest(x,z)
    elif not a and b and c:
        print greatest(y,z)
    elif not a and not b and c:
        print z
    elif not a and b and not c:
        print y
    elif a and not b and not c:
        print x
    elif a and b and c:
        print greatest(x,greatest(y,z))
    else:
        print "None of them are odd"
go(int(input()),int(input()),int(input()))

Doing the problem it felt like I am going over all the eight combinations \$2^3\$ for three variables. Is there any way to avoid this?

\$\endgroup\$
4
  • 2
    \$\begingroup\$ I have rolled back the last edit. Please see what you may and may not do after receiving answers. \$\endgroup\$
    – Heslacher
    Commented Aug 12, 2016 at 12:08
  • \$\begingroup\$ In Ruby: def greatest(*arr); arr.select(&:odd?).max; end. Given the similarity of Ruby and Python, I assume this would be little different in Python. Perhaps a someone familiar with both languages could comment. \$\endgroup\$ Commented Aug 14, 2016 at 18:41
  • \$\begingroup\$ Note that the following is correct and shorter: def odd_check(a): return a%2 \$\endgroup\$
    – boardrider
    Commented Aug 16, 2016 at 18:43
  • \$\begingroup\$ def greatest(a,b): return max(a,b) will probably be faster (and you may not need the function, just use max()inline). \$\endgroup\$
    – boardrider
    Commented Aug 16, 2016 at 18:48

6 Answers 6

28
\$\begingroup\$

You could filter out the even numbers, and then get the maximal value:

def odd_check(a):
    return not(a%2 == 0)

def go(x, y, z):
    l = [e for e in [x, y, z] if odd_check(e)]
    try:
        print(max(l))
    except ValueError:
        print("None of them are odd")
\$\endgroup\$
6
  • \$\begingroup\$ By far the most readable solution. And performance should be very much comparable. Additionally, for considerably more inputs, it may be worth it to convert l to an iterable, but not for three \$\endgroup\$ Commented Aug 12, 2016 at 14:17
  • 9
    \$\begingroup\$ The one change I would make to this is replace odd_check with a%2 One line functions that are used once are generally a bad idea. (especially when typing the function is longer than it's code. If you really care about the modularity, you should at least remove the not and ==0 as they just negate a%2 \$\endgroup\$ Commented Aug 12, 2016 at 15:35
  • 4
    \$\begingroup\$ Agreed, just a % 2 or maybe a % 2 != 0 is clearer (and note that not() isn't a function). And IMO it's simpler here to say if not l: before the max() call than having a try/except. \$\endgroup\$
    – Ben Hoyt
    Commented Aug 12, 2016 at 16:48
  • 1
    \$\begingroup\$ not is not a function, and x, y, z can be replaced with *values \$\endgroup\$
    – njzk2
    Commented Aug 13, 2016 at 0:34
  • 1
    \$\begingroup\$ Why not(a%2 == 0) instead of a%2 != 0? \$\endgroup\$
    – Sumurai8
    Commented Aug 13, 2016 at 12:07
29
\$\begingroup\$

And for those who love comprehensions...

def max_odd(*args):
     return max(x for x in args if x%2)
\$\endgroup\$
12
  • 1
    \$\begingroup\$ You don't need the [] inside the max. It happily takes a generator expression. \$\endgroup\$
    – Graipher
    Commented Aug 12, 2016 at 15:06
  • 1
    \$\begingroup\$ Where do I learn these? I can't even comprehend what is going on here. \$\endgroup\$
    – piepi
    Commented Aug 12, 2016 at 16:01
  • 2
    \$\begingroup\$ @piepi They're one of the big changes when moving to Python (or functional programming, I suppose). At first they seem terribly confusing but once you get them they make code a lot easier to follow (and possibly a bit faster). Then once you really understand them you'll abuse them and be annoyed by yourself coming back to some code a year later. They're called "list comprehensions" (there's also set and dictionary ones as well): carlgroner.me/Python/2011/11/09/… - there are plenty of other links if that one doesn't help. \$\endgroup\$
    – Tom
    Commented Aug 12, 2016 at 18:06
  • 1
    \$\begingroup\$ This is clearly the right solution in Python. \$\endgroup\$ Commented Aug 12, 2016 at 18:18
  • 7
    \$\begingroup\$ I would rather explicitly have x % 2 != 0, which has the same value, but carries more meaning, I find. \$\endgroup\$
    – njzk2
    Commented Aug 13, 2016 at 0:32
6
\$\begingroup\$

A clearer algorithm would be to filter out the even numbers and then just pick the highest value.

Here's a quick implementation using higher order functions. If you prefer list comprehensions you could probably do it just as cleanly.

def highest_odd(*args):
    odds = filter(lambda x: x % 2 != 0, args)
    if odds:
        return max(odds)
    else:
        return None

highest_odd(5,10,15) # = 15
highest_odd(1,2,4) # = 1
\$\endgroup\$
3
  • \$\begingroup\$ I understood...partially. \$\endgroup\$
    – piepi
    Commented Aug 12, 2016 at 16:00
  • \$\begingroup\$ The * before args means put all unnamed arguments to this function in a list called args. Filter() takes the list of arguments and a lambda (an inline function) as it's arguments. It runs the lambda on each element of the of the list and the ones that return true get returned in a list. max() then takes that list and returns the highest element. There's an if around max because if you give max an empty list then it throws an exception, so we avoid that and return None instead in that case. \$\endgroup\$
    – alwaysme
    Commented Aug 12, 2016 at 16:09
  • 1
    \$\begingroup\$ It's not Pythonic to use filter/lambda for this -- just use the comprehensions: odds = [x for x in args if x % 2 != 0]. \$\endgroup\$
    – Ben Hoyt
    Commented Aug 12, 2016 at 16:51
5
\$\begingroup\$

Instead of checking all 3 variables at once you could check two together and then the larger one with the remaining one.

Example: 3, 9, 1

3, 9 -> 9 is larger
9, 1 -> 9 is larger
-> 9 is the largest
\$\endgroup\$
5
  • 1
    \$\begingroup\$ I am assuming all the inputs not to be odd. \$\endgroup\$
    – piepi
    Commented Aug 12, 2016 at 11:38
  • \$\begingroup\$ No problem. Do a check if they are odd, as in your example, first. In the result of this check you could save the original number, if it was odd, or 0 if it wasn't. Afterwards the check as I wrote above. \$\endgroup\$
    – Borgiman
    Commented Aug 12, 2016 at 11:42
  • \$\begingroup\$ @piepi: Should also be checking that the input is actually a number too. \$\endgroup\$
    – Trojan404
    Commented Aug 12, 2016 at 12:00
  • \$\begingroup\$ @Morpheuz I have posted another version of the code. \$\endgroup\$
    – piepi
    Commented Aug 12, 2016 at 12:02
  • \$\begingroup\$ @piepi: CodeReview does not do iterative reviews in single questions. This defeats the purpose of the question and answer style of posts. If you would like a review of your new code, post a new question. :) \$\endgroup\$
    – Trojan404
    Commented Aug 12, 2016 at 12:10
2
\$\begingroup\$

Building on @enedil s answer, I would return the max and not print it, allowing re-usability of your function. I would also make it accept a variable number of input parameters:

def odd_check(a):
    return not(a%2 == 0)

def max_odd(*args):
    try:
        return max(e for e in args if odd_check(e))
    except ValueError:
        raise ValueError("None of the variables is odd")

args = [input() for _ in range(3)]
print(max_odd(*args))
print(max_odd(1,2,3))
print(max_odd(1,3,5,7,9))

I also gave the function a more descriptive name.

\$\endgroup\$
1
\$\begingroup\$

PiePi, this looks to have been as useful a learning experience for me as asking the question is for you. The approach you took is simply a laborious way round, not wrong, My struck out answer reveals my long-winded approach based on my history of using C and C++(hence it is struck out rather than simply edited away). However a quick look through the python inbuilt function reveals a few useful pieces:

These two functions along with a simple checker (which you already have) for the oddness of the number allow for a simple fast and effective approach.

Obliterating the bad code below (damnable habits from C/C++ I spent 5 minutes researching a more pythonic way (Thanks to @Joe-Wallis for politely pointing out!:^) )

now the code sums up to 2 two-line functions:

def IsOdd(intIn):
    return not(intIn%2==0)

def GetLargestOdd(x,y,z):
    return max(filter(IsOdd, (x,y,z)))

Ohh and used like:

print(GetLargestOdd(1,2,3))

No re-invention of the wheel or needless variables:)

\$\endgroup\$
1
  • 2
    \$\begingroup\$ This is a code review. Answers are expected to follow code style conventions, especially in Python -> PEP-8 \$\endgroup\$
    – njzk2
    Commented Aug 13, 2016 at 0:37

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.