5
\$\begingroup\$

Suppose I want to find the index of the maximal value of a given sequence. In Matlab, this is:

[value, index] = max(x)

In Python, I would abstract the following pattern:

def find_best_element_index(elements, is_better):
    best_so_far = elements[0]
    best_so_far_index = 0
    for (index, element) in enumerate(elements):
        if is_better(element, best_so_far):
            best_so_far = element
            best_so_far_index = index
    return best_so_far_index

Which I could use in the following way:

import operator
assert find_best_element_index([6, 3, 9, 8, 0, 9, 7, 9, 7, 8], operator.gt) == 2

But I wonder if there is a more pythonic way to go when I just want to find the index of the "best" item.

\$\endgroup\$

1 Answer 1

6
\$\begingroup\$
  1. I just want to find the index of the "best" item.

This can be written very shortly and readably using enumerate, first class functions and list indexing.

def index_of_max_value(items):
    return max(enumerate(items), key = lambda x: x[1])[0]

Explanation:

  1. I create a list that contains the numbers and their indexes, the index is first, the number second.
>>> list(enumerate([4,7,4,8]))
[(0, 4), (1, 7), (2, 4), (3, 8)]
  1. I ask the item that has the biggest value when a function I decide is applied to it, I do so by passing the function as the key argument, when functions are passed around like this they are first class citizens
>>> max(["rg","gu","sd"], key = lambda s: sum(map(ord,s)))
'gu'

For example in the above I asked which of the strings had the most ASCII value.

key = lambda x: x[1]

Means that I want the pair (index,number) that has the biggest 'second' item (remember zero indexing).

  1. [n] gives you the n-th item of a list, I ask the '0-th' (first) item that is the index.

I hope that you like my alternative shorter solution, if you have any doubts, fell free to ask.

\$\endgroup\$
5
  • \$\begingroup\$ Great one-liner! I didn't know that I could provide an optional key argument to max. In this way, I can use max to calculate the index of the min value too! ;) \$\endgroup\$ Commented Mar 8, 2015 at 10:33
  • \$\begingroup\$ BTW, can you confirm that the required size is constant, i.e., that max does not construct the whole list of couples? \$\endgroup\$ Commented Mar 8, 2015 at 10:43
  • 1
    \$\begingroup\$ @Aristide enumerate yields an iterator, that is like a promise or a lazy list, it is consumed value after value, so the space requirement are O(1), that is only two items in memory at any given time: the current max and the item to compare. \$\endgroup\$ Commented Mar 8, 2015 at 11:20
  • 1
    \$\begingroup\$ Sorry, my question was too broad, I have edited it in order to suppress the second part, since your answer is a perfect fit for the first one. I'll ask the second question separately. Thanks for your explanations! \$\endgroup\$ Commented Mar 8, 2015 at 12:12
  • \$\begingroup\$ @Aristide you are welcome! \$\endgroup\$ Commented Mar 8, 2015 at 19:20

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.