简体   繁体   中英

Can you explain this Python list comprehension?

def get_max(r, a, b):
    """ Returns the maximum value in the form (index, value). """
    return max([(x+a, r[a:b][x]) for x in xrange(len(r[a:b]))], key=lambda x:x[1])

Can anyone explain what this list comprehension does?

For efficiency it's a good idea to avoid repeating the slice of r over and over

chunk = r[a:b]
[(x+a, chunk[x]) for x in xrange(len(chunk))]

I think it also makes the meaning of the code a bit clearer (it's not exactly Pythonic) yet

chunk = r[a:b]
[(i, j) for i, j in enumerate(chunk, a)]

Oh it's the identity list comprehension

list(enumerate(chunk, a))

so instead of all that waffle, you can say

def get_max(r, a, b):
    """ Returns the maximum value in the form (index, value). """
    return max(enumerate(r[a:b], a), key=lambda x:x[1])

as @vonPetrushev tries to explain in the comments, you can replace the lambda function with an itemgetter.

from operator import itemgetter
def get_max(r, a, b):
    """ Returns the maximum value in the form (index, value). """
    return max(enumerate(r[a:b], a), key=itemgetter(1))

There isn't much performance difference and the itemgetter version is more descriptive (as long as you know what itemgetter does)

Let's break it down into pieces.

First, here's just the listcomp on its own:

[(x+a, r[a:b][x]) for x in xrange(len(r[a:b]))]

That's equivalent to this loop:

result=[]
for x in xrange(len(r[a:b])):
    result.append((x+a, r[a:b][x]))

So, what does each part do?

r[a:b] is the sub-sequence of r from index a (inclusive) to b (exclusive). So len(r[a:b]) is almost a fancy way of saying ba , but not quite—because b could be past the end of the sequence, or either one of the indices could be negative indices. And xrange(len(r[a:b])) is just all the numbers from 0 up to that length (again exclusive).

Now, for each of these numbers x from 0 to that length, we create a tuple (x+a, r[a:b][x]) .

Let's work through an example:

>>> r = ['a', 'b', 'c', 'd', 'e', 'f']
>>> a = 2
>>> b = 4
>>> r[a:b]
['c', 'd']
>>> len(r[a:b])
2
>>> list(xrange(len(r[a:b])))
[0, 1]
>>> x=0
>>> (x+a, r[a:b][x])
(2, 'c')
>>> x = 1
>>> (x+a, r[a:b][x])
(3, 'd')

So, as you can see, it's creating a list of (index, value) for the indices from a to b , like this:

[(2, 'c'), (3, 'd')]

A much nicer way to write the same thing is:

>>> list(enumerate(r))[a:b]
[(2, 'c'), (3, 'd')]

… or …

>>> list(enumerate(r[a:b], a)
[(2, 'c'), (3, 'd')]

r is a sequence, a is a starting index, and b is an ending index. The list comprehension will give a list of (index, r[index]) tuples where a <= index < b . The max() call will then return the tuple with the largest value (second item in the tuple).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM