简体   繁体   中英

Why does the map object in Python 3 need to be cast to a list to function with comprehension?

This question comes from a hackerrank question from basic data types. When I run

max(map(int, range(5)))

I get the right output of 4, however when I do

if __name__ == '__main__':
    n = int(input()) #this line seems irrelevant to my question, but it was present in the original question so I have included it here for completeness
    arr = map(int, input().split())
    print(max([x for x in arr if x < max(arr)]))

and give input

5
2 3 6 6 5

the result is 2. However if I first cast the map object to a list I get the correct answer of 5. This is further bewildering as when I replace the print argument with

print(max(arr))

it gives the correct answer of 6, so clearly max works, but I'm guessing something in the list comprehension breaks on map objects for some reason. This is especially supported by the fact that if I do

print([x for x in arr if x < max(arr)])

I get 2. More testing with other less ordered lists shows that the last statement seems to always return list(arr)[0], so ultimately I expect the issue is with the list comprehension on the map objects. So ultimately what I'd like to know is

  • How does Python 3.5.x deal with map objects and list comprehensions which is causing the failure?
  • Is there any way to successfully process the map object in a straightforward way with a comprehension that does not involve casting?

The return value of map in Python 3 is not a list, but an iterable object. It can easily be turned into a list, but if you use it directly, it can't be iterated multiple times. If you iterate it once in order for max to be calculated, you have used it up, and you won't get all the items again.

In Python 2, map built a list for you, so you didn't get the option of lazily evaluating the items inside it. In Python 3, you can pass it to the list function to get a list.

In Python 3, map gives you an iterator . So arr gives you the numbers 2, 3, 6, 6 and 5 once . When you do [x for x in arr if x < max(arr)])) , the for x in arr asks arr for its next element, which is 2 , and assigns that to x . Then the max(arr) goes over the remaining numbers (3, 6, 6 and 5) and returns the maximum, which is 6 . Since 2 is less than 6 , it ends up in your result. Then the for x in arr goes again, and since arr already went through everything, we're finished. So that's why your result is [2] .

You're wrong about the list always containing the first element, though. If you for example enter 4 3 2 1 , then the resulting list is empty (because 4 isn't less than the maximum of 3, 2 and 1).

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