hugo.r
hugo.r

Reputation: 13

The sum() function seems to be messing map objects

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.

Upvotes: 0

Views: 236

Answers (2)

Simon Bowly
Simon Bowly

Reputation: 1093

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.

Upvotes: 4

Ajax1234
Ajax1234

Reputation: 71471

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

Upvotes: 1

Related Questions