Ouroboros
Ouroboros

Reputation: 19

map from a list comprehension?

I came across this scraping problem which itself is irrelevant but want to know if it is possible to perform map() from a list comprehension meaning the iterable be a list comprehension?

The following returns the empty list where I expected [0, 2, 4, 6, 8] :

def foo() -> list[int]:
    result: list = []
    map(result.append, [x for x in range(10) if x % 2 == 0])
    print(result)

I guess the question is could the iterable for map function itself be a list comprehension or not? This specific example isn't itself important.

Upvotes: -3

Views: 66

Answers (3)

Louis P
Louis P

Reputation: 33

Your code doesn't work because the map function returns an iterator so as you didn't iterate over the object returned by map, the result.append function is never called.

The "just working" version of your code would be something like:

def foo() -> list[int]:  # Note that the type hint here is incorrect as you don't return anything
    result: list = []
    tuple(map(result.append, [x for x in range(10) if x % 2 == 0]))
    print(result)

But this is very unoptimized, the version I would write would use directly the list comprehension:

def foo():
    print([x for x in range(10) if x % 2 == 0])

Otherwise you could use a filter:

def foo():
    print(list(filter(lambda x: x % 2 == 0, range(10))))

For more information, please read this article: https://realpython.com/python-map-function/

Upvotes: 3

David Maze
David Maze

Reputation: 159752

The second argument to map can be any iterable, including a list comprehension. That's fine.

The actual problem is that map itself returns an iterable, that doesn't do anything until it's consumed. You could put this itself in something like a for loop, like

result: list[int] = []
iter = map(result.append, [x for x in range(10) if x % 2 == 0])
for x in iter:
  print(f"This is the result of result.append, which is None: {x}")
print(result)

Note that the list comprehension itself is just syntactic sugar around map and filter, but putting it in list syntax forces the iterator to be resolved to a list, rather than a lazy iterable.

evens1 = [x for x in range(10) if x % 2 == 0]
evens2 = list(map(filter(range(10), lambda x: x % 2 == 0), lambda x: x))

Correspondingly in your own code, you could evaluate the map result to a list and then discard it immediately; that would also work.

result: list = []
list(map(result.append, [x for x in range(10) if x % 2 == 0]))
#^^^
print(result)

(In the setup you show, result is expected to be identical to the input list. More generally you can use map or a list comprehension instead of iterating and using result.append, and this more functional style may be a little more compact and easier to read.)

Upvotes: 2

mkrieger1
mkrieger1

Reputation: 23250

Of course, a list comprehension evaluates to a list, which is an iterable suitable for map.

The problem in your case is that the iterator returned by map is never used, so result.append is never called.

Upvotes: 4

Related Questions