user1554752
user1554752

Reputation: 645

Using * idiom to unpack arguments when using map()

Is there a way to unpack a tuple with the * idiom when using the map built-in in Python?

Ideally, I'd like to do the following:

def foo(a, b):
  return a**2 + b

x = [(1,2), (3,4), (5,6)]

results = map(foo, *x)

where results would equal [3, 13, 31]

Upvotes: 2

Views: 109

Answers (3)

Karl Knechtel
Karl Knechtel

Reputation: 61635

As it happens, map accepts *args, so your original call map(foo, *x) doesn't immediately fail - but what happens is that each element from x is treated as a sequence of values for one argument to foo - so it attempts foo(1, 3, 5) and would then attempt foo(2, 4, 6) except of course that foo only accepts 2 arguments.

Since we can see that our input x is effectively the "matrix transpose" of what we would like to feed in, that directly points us to a workaround:

>>> list(map(foo, *zip(*x))) # list() wrapping for 3.x support
[3, 13, 31]

... But don't do that. Use itertools.starmap; it's built for this and considerably clearer about your intent.

Upvotes: 1

Mauro Baraldi
Mauro Baraldi

Reputation: 6575

An uglier way than the @roippi's way...

x = [(1,2), (3,4), (5,6)]

map(lambda y:y[0]**2 + y[1], x)

Upvotes: 1

roippi
roippi

Reputation: 25974

You're looking for itertools.starmap:

def foo(a, b):
  return a**2 + b

x = [(1,2), (3,4), (5,6)]

from itertools import starmap

starmap(foo, x)
Out[3]: <itertools.starmap at 0x7f40a8c99310>

list(starmap(foo, x))
Out[4]: [3, 13, 31]

Note that even in python 2, starmap returns an iterable that you have to manually consume with something like list.

Upvotes: 7

Related Questions