问题
I'm doing this code excercise for trying out functional programming in python, and I ran into problems with sum(), list(), and map objects. I don't understand what I'm doing wrong, but the list() function seems to be screwing with my map object.
This is the code I have:
people = [{'name': 'Mary', 'height': 160},
{'name': 'Isla', 'height': 80},
{'name': 'Sam'}]
heights = map(lambda x: x['height'], filter(lambda x: 'height' in x, people))
print(len(list(heights)))
print(sum(list(heights)))
print(len(list(heights)))
average_height = sum(list(heights)) / len(list(heights))
print(average_height)
heights should be a map object containing (or resulting in) a list of the two existing height entries: [160, 80].
printing the length should give 2, the sum of the two should obviously be 240, and the average should be 120.
The problem I'm facing, though, is that I get this error message:
2
0
0
Traceback (most recent call last):
File "C:\Users\Hugo\Dropbox\Programmering\PythonProjekt\exercise2.py", line 12, in <module>
average_height = sum(list(heights)) / len(list(heights))
ZeroDivisionError: division by zero
Yes, the length is right, but the sum is 0, and the second length print is 0 aswell. The whole zero-division fault must come from something there, and it seems that the list() function is causing it. Changing the print order still only lets through the first print statement correctly:
print(sum(list(heights)))
print(len(list(heights)))
print(len(list(heights)))
Gives:
240
0
0
Traceback (most recent call last):
File "C:\Users\Hugo\Dropbox\Programmering\PythonProjekt\exercise2.py", line 12, in <module>
average_height = sum(list(heights)) / len(list(heights))
ZeroDivisionError: division by zero
and removing the list() function:
print(sum(list(heights)))
print(len(heights))
print(len(list(heights)))
gives me:
240
Traceback (most recent call last):
File "C:\Users\Hugo\Dropbox\Programmering\PythonProjekt\exercise2.py", line 9, in <module>
print(len(heights))
TypeError: object of type 'map' has no len()
So I have no idea what's going on. The list() function should not be changing the map object in any way, right? And it stays a map object, but calling list() on it more than once seems to change its behaviour. I am confuse.
回答1:
Actually, calling list
does change your map
object. map
is an iterator, not a data structure (in Python3). After it has been looped over once, it is exhausted. To reproduce the result, you need to recreate the map object.
In your case, what you probably want to do is create a list from the map to store the result, then perform the sum
.
heights = list(heights)
average = sum(heights) / len(heights)
Edit: another approach.
You can calculate arithmetic mean (and other statistics) directly from iterators using the statistics module. Check out the docs.
回答2:
You can create a list by iterating over your map
structure to avoid exhausting the iterator with every list call:
people = [{'name': 'Mary', 'height': 160},
{'name': 'Isla', 'height': 80},
{'name': 'Sam'}]
heights = [i for i in map(lambda x: x['height'], filter(lambda x: 'height' in x, people))]
average_height = sum(heights)/len(heights)
Output:
120.0
来源:https://stackoverflow.com/questions/47972274/the-sum-function-seems-to-be-messing-map-objects