7

I'm trying to map a function that takes 2 arguments to a list:

my_func = lambda index, value: value.upper() if index % 2 else value.lower()

import string
alphabet = string.ascii_lowercase

n = map(my_func, enumerate(alphabet))
for element in n:
    print(element)

This gives me a TypeError: <lambda>() missing 1 required positional argument: 'value'.

What is the correct way to map my lambda onto this input?

4
  • 2
    yep, python 3 cannot automatically unpack lambda arguments anymore. Commented Apr 26, 2018 at 11:50
  • 1
    I stand corrected: it doesn't work on any python version... Commented Apr 26, 2018 at 11:57
  • Did an answer below help? Feel free to accept an answer (green tick on left), or ask for clarification. Commented May 8, 2018 at 11:15
  • This great answer was replied on a "duplicate" thread stackoverflow.com/a/47045710/1265070 Commented Jan 21, 2024 at 7:10

3 Answers 3

8

map will pass each value from enumerate as a single parameter to the callback, i.e. the lambda will be called with a tuple as argument. It would be pretty surprising behaviour if map would unpack arguments which look unpackable, since then its behaviour would depend on the values it iterates over.

To expand iterable arguments, use starmap instead, which "applies a * (star)" when passing arguments:

from itertools import starmap

n = starmap(lambda index, value: ..., enumerate(alphabet))
Sign up to request clarification or add additional context in comments.

Comments

4

Python cannot unpack lambda parameters automatically. enumerate returns a tuple, so lambda has to take that tuple as sole argument

You need:

n = map(lambda t: t[1].upper() if t[0] % 2 else t[1], enumerate(alphabet))

Considering now the ugliness of map + lambda + manual unpacking, I'd advise the alternate generator comprehension instead:

n = (value.upper() if index % 2 else value for index,value in enumerate(alphabet))

(I removed the lower() call since your input is already lowercase)

1 Comment

Hi, Sorry for that bad formatting of my code, I just don't know hot ot do that. I'll do it correctly next time. Thank you Jean-François Fabre, I've already done this with comprehension, then I tried to do the same by map() to examine myself. Yor explanation is good, something new to me. Regards
4

Python can't unpack lambda parameters automatically.

But you can get round this by passing an extra range argument to map:

import string

alphabet = string.ascii_lowercase

n = map(lambda i, v: v.upper() if i % 2 else v.lower(),
        range(len(alphabet)),
        alphabet)

for element in n:
    print(element)

As per the docs:

map(function, iterable, ...)

Return an iterator that applies function to every item of iterable, yielding the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted. For cases where the function inputs are already arranged into argument tuples, see itertools.starmap().

6 Comments

I never imagined that map could take more than 1 iterable!
@Jean-FrançoisFabre, Yeh it's just one of those tricks you see once and are so surprised you cannot possibly forget.
Also, this is what I love about SO.. 3 equally acceptable answers within 10 mins!
and completely different as well!
Please split that n = map(...) line into multiple shorter ones. Having to scroll just to see the solution isn't great for the readability of the answer. I'd assign the lambda to a variable. Or you can just refer to the lambda as my_func, like the code in the question does.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.