简体   繁体   中英

Working of Enumerate in Python

I'm new to Python and I'm currently solving questions to improve my coding skills. I came across the question where I to find the maximum value in a List and it's corresponding value in an other List with the same index number of the maximum value.

for example: I have two Lists with values L1 = [9, 12, 9 ,6] and L2 = [2, 3, 4, 5] I have to find the maximum value in the List L1 and the index of the maximum value should be used in List L2 to find it's corresponding value.

Max value in List L1 - 12
Index of the max value - 1
print L2[1] -> 3

So to achieve the above logic, I have re-searched a way and obtained it. But I'm not able to understand how the logic is working.

import operator   
index, value = max(enumerate(l1), key=operator.itemgetter(1))
print value, 
print l2[index]

OUTPUT: 12 3

To understand how the above function is working, I tried to print each section separately but still not able to understand how the logic is working.

print l1 - [9, 12, 9 , 6]
print l2 - [2, 3, 4, 5]
print list(enumerate(l1)) - [<0, 9>, <1, 12>, <2, 9>, <3, 6>]
print list(enumerate(l2)) - [<0, 2>, <1, 3>, <2, 4>, <3, 5>]
print max(enumerate(l1)) - <3, 6>
print max(enumerate(l2)) - <3, 5>

Please help me in understanding how the enumerate function and key=operator.itemgetter(1))[0] is working in the above logic. Thanks in advance. Your help is much appreciated.

enumerate() simply produces tuples with the original value plus an index, in the order (index, item) , for each item in the input iterable. See What does enumerate mean?

max() picks out the maximum value from a sequence, given a key. The default key is to use the value itself, but with operator.itemgetter(1) , you are telling max() to only pay attention to the second value of each input item.

You could easily play with this to see that max() always returns an original value from the list, but alters what value is returned when using a key function. You can use any function, including one created with a lambda :

>>> L1 = [9, 12, 9, 6]
>>> max(L1)  # straight up, biggest value in the list
12
>>> max(L1, key=lambda v: len(str(v)))  # value with the most digits, 12 has two digits
12
>>> max(L1, key=lambda v: abs(v - 10))  # value furthest from 10; 6 is the furthest
6

When you call operator.itemgetter() with at least one argument, it'll produce an object that when called with a sequence , will use the argument(s) as indices for that sequence. operator.itemgetter(1) creates an object that always picks the second element (Python starts counting from 0 ), operator.itemgetter(2) would return the 3rd element each time you call it:

>>> from operator import itemgetter
>>> ig2 = itemgetter(2)
>>> ig2
operator.itemgetter(2)
>>> ig2(L1)  # the 3rd element in L1 is 9
9

Given that enumerate() puts the original value in the second position of each tuple it produces, max() picking the maximum value from the sequence of tuples based on the value from the original input list. It'll keep the tuples produced by enumerate() intact however.

If you omitted the key , you'd get the biggest 'tuple'; tuples are compared by the first element contained that is different. So (1, 2) is bigger than (1, 0) because the second element, 2 is bigger than 0 . But (2, 1) is bigger than (1, 1) because the first element differs and 2 is the larger one. Since enumerate() adds increasing indices (starting at 0 ) that means max() without a key will always pick the last element:

>>> max(enumerate(l1))  # last element is (3, 6)
(3, 6)

That element was picked because 3 is the highest index.

Note that using enumerate() is overkill here. You could just use the zip() function to pair up L1 and L2 instead:

l1max, corresponding_l2 = max(zip(L1, L2))

zip() pairs up the elements of L1 and L2 , producing tuples with (9, 2) , (12, 3) , etc. max() picks the biggest tuple from that sequence, looking first at the first element (taken from L1 ).

enumerate creates a generator function that effectively turns a list of values into a list of tuples.

L1 = [9, 12, 9, 6]

becomes

[(0, 9), (1, 12), (2, 9), (3, 6)]

The max function finds the maximum value in that list. If no other arguments were provided to max , it would compare the tuples to each other and this item would be the max - (3, 6) . But that's not what we want. We don't want it to use the enumerate number in the comparison.

max accepts a key argument, which should be a function that takes one argument, which will be the value from the list, and should return a value that will be used to sort the list and choose a maximum. In this case, we want to sort the list based on the second number in each tuple (ie the 6 in (3, 6) ).

operator.itemgetter is a function that returns a function, which will return an indexed item of the thing it's called on. For example:

L1 = [3, 4, 6, 2]
f = operator.itemgetter(0)
f(L1)
# 3

f = operator.itemgetter(2)
f(L1)
# 6

In this case, it uses operator.itemgetter(1) , which is going to return the 6 in (3, 6)

So the result we get from max(enumerate(l1), key=operator.itemgetter(1)) is a tuple with the index of the max value and the max value in L1 .

From the help:

Help on built-in function max in module builtins:

max(...) max(iterable, *[, default=obj, key=func]) -> value max(arg1, arg2, *args, *[, key=func]) -> value

 With a single iterable argument, return its biggest item. The default keyword-only argument specifies an object to return if the provided iterable is empty. With two or more arguments, return the largest argument. 

And the

Help on class itemgetter in module operator:

class itemgetter(builtins.object) | itemgetter(item, ...) --> itemgetter object | | Return a callable object that fetches the given item(s) from its operand. | After f = itemgetter(2), the call f(r) returns r[2]. | After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])

So, itemgetter does what its name says: it gets the specified item(s) from the elements of a list. In this case, the second elements (those with index 1). This is what you do:

You call max on the output generated by enumerate:

[<0, 9>, <1, 12>, <2, 9>, <3, 6>]

and tell it to determine the maximum based on the key defined by:

key=operator.itemgetter(1)),

that is, the second value of each element in the list. Then max returns the element it found, which is of the form (index, value).

@Dev: The Enumerate function just prints the list and its index value and key is something you want to operate with respect to data structure , Please find the code below

index, value = min(enumerate(l1), key=operator.itemgetter(1))
print value
6
print index
3
index, value = max(enumerate(l1), key=operator.itemgetter(1))
print index
1
print value
12
sorted(enumerate(l1), key=operator.itemgetter(1))
[(3, 6), (0, 9), (2, 9), (1, 12)]
sorted(enumerate(l1), key=operator.itemgetter(0))
[(0, 9), (1, 12), (2, 9), (3, 6)]

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