3

I'm trying to create a function that returns the largest element of an array, I feel I have the correct code but my syntax is in the wrong order, I'm trying to use a for/while loop in order to do so. So far I have the following:

def manindex(arg):

    ans = 0

    while True:
    for i in range (len(arg)):
        if arg[i] > arg[ans]:
            pass

            ans = i

    return ans

Not sure where I'm going wrong if anyone could provide some guidance, thanks

EDIT: So it's been pointing out I'm causing an infinite loop so if I take out the while statement I'm left with

def manindex(arg):

ans = 0

for i in range (len(arg)):
 if arg[i] > arg[ans]:

ans = i

return ans

But I have a feeling it's still not correct

3
  • 1
    you should not use both of then it is an infinite loop because the while True statement will never stop Commented Jan 3, 2015 at 14:27
  • Okay so If I take away the while true statement, I'll be left with def manindex(arg): ans = 0 for i in range (len(arg)): if arg[i] > arg[ans]: ans = i return and This still doesn't seem to be quite right Commented Jan 3, 2015 at 14:29
  • What if there is more than one element with the same largest value? Commented Jan 3, 2015 at 16:26

6 Answers 6

7

When you say array I think you mean list in Python, you don't need a for/loop or while/loop to achieve this at all.

You can also use index with max, like so:

xs.index(max(xs))

sample:

xs = [1,123,12,234,34,23,42,34]

xs.index(max(xs))
3
Sign up to request clarification or add additional context in comments.

3 Comments

Just as a quick note: unlike some of the other answers, this approach will likely walk through the list twice, once for the max and once for the index. If your lists are insanely large, a hand-written loop might be faster - but measure carefully just to be sure, and decide if the loss of elegance is worth the speedup, if any.
@WanderNauta, I totally agree that index will indeed introduce another loop. (not arguing but) I think by shifting the loop from python to C level listindex, making use of python built-in (elegance), is worth the consideration. I think my approach using list.index(max(list)) may still be the fastest thus far among other solutions.
@WanderNauta, out of curiosity, I've just tried to measure the performance and provided that my list is a range(99999), %timeit results are: index(max) => 3.32 ms per loop, argmax => 8.58 ms per loop, max_element_index => 7 ms per loop.
1

You could use max with the key parameter set to seq.__getitem__:

def argmax(seq):
    return max(range(len(seq)), key=seq.__getitem__)

print(argmax([0,1,2,3,100,4,5]))

yields

4

Comments

1

The idea behind finding the largest index is always the same, iterating over the elements of the array, compare to the max value we have at the moment, if it's better, the index of the current element is the maximum now, if it's not, we keep looking for it.

enumerate approach:

def max_element_index(items):
    max_index, max_value = None, None
    for index, item in enumerate(items):
        if item > max_value:
             max_index, max_value = index, item
    return max_index

functional approach:

def max_element_index(items):
    return reduce(lambda x,y: x[1] > y[1] and x or y, 
                  enumerate(items), (None, None))[0]

At the risk of looking cryptic, the functional approach uses the reduce function which takes two elements and decides what is the reduction. Those elements are tuples (index, element), which are the result of the enumerate function.

The reduce function, defined on the lambda body takes two elements and return the tuple of the largest. As the reduce function reduces until only one element in the result is encountered, the champion is the tuple containing the index of the largest and the largest element, so we only need to access the 0-index of the tuple to get the element.

On the other hand if the list is empty, None object is returned, which is granted on the third parameter of the reduce function.

1 Comment

a lot an answers posted. answers that use "l.index(max(l))" iterate through the list twice. O2n. this is On and the right approach. Also using enumerate is the right thing to do in these thep problems.
1

Before I write a long winded explanation, let me give you the solution:

index, value = max(enumerate(list1), key=lambda x: x[1])

One line, efficient (single pass O(n)), and readable (I think).

Explanation

In general, it's a good idea to use as much of python's incredibly powerful built-in functions as possible.

In this instance, the two key functions are enumerate() and max().


enumerate() converts a list (or actually any iterable) into a sequence of indices and values. e.g.

>>> list1 = ['apple', 'banana', 'cherry']
>>> for tup in enumerate(list1):
...     print tup
...
(0, 'apple')
(1, 'banana')
(2, 'cherry')


max() takes an iterable and returns the maximum element. Unfortunately, max(enumerate(list1)) doesn't work, because max() will sort based on the first element of the tuple created by enumerate(), which sadly is the index.

One lesser-known feature of max() is that it can take a second argument in the form max(list1, key=something). The key is a function that can be applied to each value in the list, and the output of that function is what gets used to determine the maximum. We can use this feature to tell max() that it should be ranking items by the second item of each tuple, which is the value contained in the list.

Combining enumerate() and max() with key (plus a little help from lambda to create a function that returns the second element of a tuple) gives you this solution.

index, value = max(enumerate(list1), key=lambda x: x[1])

I came up with this recently (and am sprinkling it everywhere in my code) after watching Raymond Hettinger's talk on Transforming Code into Beautiful, Idiomatic Python, where he suggests exorcising the for i in xrange(len(list1)): pattern from your code.

Alternatively, without resorting to lambda (Thanks @sweeneyrod!):

from operator import itemgetter
index, value = max(enumerate(list1), key=itemgetter(1))

2 Comments

You could also do operator.itemgetter(1) in place of the lambda.
@sweeneyrod: Thanks, that's a fantastic point, added to answer.
0

I believe if you change your for loop to....

for i in range (len(arg)):
    if arg[i] > ans:
        ans = arg[i]

it should work.

Comments

0

You could try something like this. If the list is empty, then the function will return an error.

m is set to the first element of the list, we then iterate over the list comparing the value at ever step.

def findMax(xs):
    m = xs[0]
    for x in xs:
        if x > m:
            m = x
    return m

findMax([]) # error findMax([1]) # 1 findMax([2,1]) # 2

if you wanted to use a for loop and make it more generic, then:

def findGeneric(pred, xs):
    m = xs[0]
    for x in xs:
        if pred(x,m):
            m = x
    return m

findGeneric(lambda a,b: len(a) > len(b), [[1],[1,1,1,1],[1,1]]) # [1,1,1,1]

Comments

Your Answer

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.