1

I have very little experience in coding and I'm learning Python in a class. I'm learning about conditionals and loops and have been asked to create a function that'll take an arbitrary amount of arguments and give me the maximum. Obviously I'm not allowed to use the built-in max function.

So far, I have:

def max(x):
    current_max = x[1]
    for i in x[i]:
        if x[i] > current_max:
            current_max = x[i]

When I run the code, it gives me no errors, but when I try to run max() it'll only accept one argument. The only idea that came to mind was adding in:

x = input('Enter numbers to compare:')

When I ran this, I got:

UnboundLocalError: local variable 'i' referenced before assignment

And I'm unsure of what I can do at this point as I'm unsure of whether or not I'm not defining the argument correctly or there's just an error in the code defining max(x) that didn't show up in the first time for some reason.

BRamses
  • 105
  • 1
  • 2
  • 6
  • Just a remark, you are not taking a random number of arguments. Your function takes exactly one argument. N-Arguments in python would be `max(*args)`. – RedX Feb 06 '15 at 07:11
  • That's interesting, I was unaware you could do that. How would I reference the argument when I'm defining the function? So, for example, when I wrote "for i in x", what would I put in place of "x"? – BRamses Feb 06 '15 at 07:16
  • It is just a list: `for a in args`. See [this post](http://stackoverflow.com/questions/36901/what-does-double-star-and-star-do-for-python-parameters) for more details. – RedX Feb 06 '15 at 07:19
  • Thank you,I'll look into it and see if I can rewrite the function using *args instead. Seems useful to know. – BRamses Feb 06 '15 at 07:27

3 Answers3

0

x[i] is executed before the loop is for processed by the compiler so trying to loop through x[i] without i being declared beforehand will result in an error.

Given x where x is the list x = [ 1,2,3,4 ] the following should work

def max(x):
    current_max = x[0]
    for i in x:
        if i > current_max:
            current_max = i
    return current_max


x = [1,2,3,4]
print max(x)
  • Ah, okay. I understand why I was getting the error now, thank you. I tried this however and it ended up telling me the tuple index was out of range. Assigning x = [1,2,3,4] just changed the type, but still gave me the same error. (list index out of range) – BRamses Feb 06 '15 at 07:11
  • Apologies. Try my example now. – David Parlevliet Feb 06 '15 at 07:16
  • What if `x` is empty? – Ulrich Eckhardt Feb 06 '15 at 07:19
  • Yep, that works! Thank you, I think I have a better grasp of things now. – BRamses Feb 06 '15 at 07:26
  • 1
    It would raise an IndexError Exception, naturally, which would need to be handled. I don't think that returning None, 0 or False is better than receiving an exception in this case since the application is to derive the max value from a list. Not having a list to work with should be handled before max() is called otherwise you should rightfully receive an Exception which will help point you in the right direction – David Parlevliet Feb 06 '15 at 07:28
0

Two things:

1) In Python, you need to add a single * before the argument to indicate that the argument is actually a list of arguments. Without that *, you're function is only going to expect a single argument. EDIT: Ah I just saw you are actually passing a list object into your function, in which case the * isn't needed. If you wanted to support a call such as max(1,3,7,-4) then you would indeed want a *.

2) When iterating through a list, or any other "iterable", you can use for item in list_of_items: to iterate over and examine each item in the list. This is used all the time in Python and is the preferred way (ie. the Pythonic way) to iterate over the list of args in a case such as this.

Here's an example max function that ties it all together (and supports a call such as max(1,5,7,3):

def max(*x):
    current_max = x[0]  # Note we're assuming at least one argument was passed in. What if nothing was passed in?
    for i in x:
        if i > current_max:
            current_max = i
    return current_max

And here's an example max function that supports a call such as max([1,5,7,3]):

def max(x):
    current_max = x[0]  # Note we're assuming at least one argument was passed in. What if nothing was passed in?
    for i in x:
        if i > current_max:
            current_max = i
    return current_max

FYI My examples are not the best solutions to this problem, so I suggest you expand on them for your final solution.

Sean Azlin
  • 886
  • 7
  • 21
  • Thank you for both examples. I hadn't thought of simply inputting x as a list. This also illustrates how to use *x very well. Much appreciated! – BRamses Feb 06 '15 at 07:36
0

Your algorithm will work but there are two small problems. First, there is a problem with iterating over an array. Normally you don't need indexes at all, just do:

some_list = [1, 2, 3]
for item in some_list:
    print item
# Will print 1, then 2 and finally 3

Also you need to return current_max when you are done with your loop.

Reusing names of builtin functions is not a great idea, so I'd call it my_max or something like that. If you also want to check your arguments and add a docstring, you'll end up with this:

def my_max(x):
    """ Return the biggest item in an iterable. """

    if len(x) == 0:
        raise ValueError("my_max() arg is an empty sequence")

    current_max = x[0]

    for i in x:
        if i > current_max:
            current_max = i

    return current_max

If you prefer a functional coding style, you can use reduce to reduce your list to the biggest element. Simply define the lambda that returns the biggest element:

def my_max(xs):
    return reduce(lambda x, y: x if x > y else y, xs)

If you wonder how Python's built-in max is defined, it's actually written in C like many of Python's built-in functions. You can check it out on GitHub if you're curious. Internally it works just as min, since comparisons are done using something called PyObject_RichCompareBool that can compare two objects in different ways (less, less or equal, equal, not equal, ...)

André Laszlo
  • 15,169
  • 3
  • 63
  • 81