182

Let's say we have a function add as follows

def add(x, y):
    return x + y

we want to apply map function for an array

map(add, [1, 2, 3], 2)

The semantics are I want to add 2 to every element of the array. But the map function requires a list in the third argument as well.

Note: I am putting the add example for simplicity. My original function is much more complicated. And of course option of setting the default value of y in add function is out of question as it will be changed for every call.

wjandrea
  • 16,334
  • 5
  • 30
  • 53
Shan
  • 16,043
  • 36
  • 84
  • 124
  • 21
    this is exactly the same as in Lisp: `map(add,[1,2,3],[2]*3)` in general `map` takes in a function as its first argument, and if this function takes **K** argument, you have to follow up with **K** iterable: `addTriple(a,b,c) -> map(addTriple,[...],[...],[...])` – watashiSHUN Oct 19 '15 at 22:58

15 Answers15

216

One option is a list comprehension:

[add(x, 2) for x in [1, 2, 3]]

More options:

a = [1, 2, 3]

import functools
map(functools.partial(add, y=2), a)

import itertools
map(add, a, itertools.repeat(2, len(a)))
Sven Marnach
  • 483,142
  • 107
  • 864
  • 776
  • 1
    yup, but how fast is it in comparison to map function? – Shan May 31 '12 at 13:51
  • @Shan: Very similar, especially if `add()` is a non-trivial function – Sven Marnach May 31 '12 at 13:52
  • @Shan: list comprehensions are about 15% faster on my box. – Fred Foo May 31 '12 at 13:53
  • I am using map function because my data set id very large and python loops are taking very long... – Shan May 31 '12 at 13:54
  • 2
    @Shan: Take a look at NumPy in this case. If this really is an issue for you, the speed difference between list comprehensions and `map()` won't help either way. – Sven Marnach May 31 '12 at 13:54
  • 3
    @Shan: As I said before, have a look at NumPy. It might help speeding up loops conderably, provided they can be vectorised. – Sven Marnach May 31 '12 at 13:58
  • Why are you passing `len(a)` to the `repeat`? Just use an infinite iterator; it's shorter, cheaper, and exactly what the docs suggest as the primary use for `repeat`. – abarnert Nov 19 '14 at 19:29
  • 1
    @abarnert: It's unclear whether the OP is using Python 2 or 3. To make sure the example works in Python 2, I included the parameter. (Note that `map()` behaves like `zip_longest()` in Python 2, while it behaves like `zip()` in Python 3.) – Sven Marnach Nov 22 '14 at 18:31
  • Thanks for suggesting `partial`, it's a great replacement for using `starmap` and repeat for passing multiple constants to a function along with a single list of dynamic values. – Rebs Jul 22 '16 at 01:55
78

The docs explicitly suggest this is the main use for itertools.repeat:

Make an iterator that returns object over and over again. Runs indefinitely unless the times argument is specified. Used as argument to map() for invariant parameters to the called function. Also used with zip() to create an invariant part of a tuple record.

And there's no reason for pass len([1,2,3]) as the times argument; map stops as soon as the first iterable is consumed, so an infinite iterable is perfectly fine:

>>> from operator import add
>>> from itertools import repeat
>>> list(map(add, [1,2,3], repeat(4)))
[5, 6, 7]

In fact, this is equivalent to the example for repeat in the docs:

>>> list(map(pow, range(10), repeat(2)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

This makes for a nice lazy-functional-language-y solution that's also perfectly readable in Python-iterator terms.

abarnert
  • 313,628
  • 35
  • 508
  • 596
  • 3
    +1 This should be the accepted answer. It extends to any number of parameters, of course, with some constant and others lists or generators. E.g.: `def f(x,y,z): \\ return '.'.join([x,y,z])` and then: `list(map(f, list('abc'), repeat('foo'), list('defgh')))` returns `['a.foo.d', 'b.foo.e', 'c.foo.f']`. – Pierre D May 13 '16 at 21:23
  • 6
    In Python 2, it's necessary to provide the length argument to `repeat()`, since `map()` will run until the _longest_ iterator is exhausted in that version of Python, filling in `None` for all missing values. Saying that "there's not reason" to pass the parameter is wrong. – Sven Marnach Jul 22 '16 at 10:27
  • @SvenMarnach 's comment is not minor: [Python 3](https://docs.python.org/3/library/functions.html#map) and [Python 2](https://docs.python.org/2/library/functions.html#map) 's behaviour varies drastically! – Agustín Dec 19 '18 at 09:34
41

Use a list comprehension.

[x + 2 for x in [1, 2, 3]]

If you really, really, really want to use map, give it an anonymous function as the first argument:

map(lambda x: x + 2, [1,2,3])
Fred Foo
  • 328,932
  • 68
  • 689
  • 800
21

Map can contain multiple arguments, the standard way is

map(add, a, b)

In your question, it should be

map(add, a, [2]*len(a))
Yi.ding
  • 211
  • 2
  • 2
  • Not sure what his question meant to but i think add accept 2 value and those 2 are not fixed and should come from user like arg1 is coming. so in this case how we should call add(x, y) under map? – Bimlesh Sharma Dec 24 '18 at 05:18
18

The correct answer is simpler than you think. Simply do:

map(add, [(x, 2) for x in [1,2,3]])

And change the implementation of add to take a tuple i.e

def add(t):
   x, y = t
   return x+y

This can handle any complicated use case where both add parameters are dynamic.

Simon Ndunda
  • 641
  • 6
  • 9
16

Sometimes I resolved similar situations (such as using pandas.apply method) using closures

In order to use them, you define a function which dynamically defines and returns a wrapper for your function, effectively making one of the parameters a constant.

Something like this:

def add(x, y):
   return x + y

def add_constant(y):
    def f(x):
        return add(x, y)
    return f

Then, add_constant(y) returns a function which can be used to add y to any given value:

>>> add_constant(2)(3)
5

Which allows you to use it in any situation where parameters are given one at a time:

>>> map(add_constant(2), [1,2,3])
[3, 4, 5]

edit

If you do not want to have to write the closure function somewhere else, you always have the possibility to build it on the fly using a lambda function:

>>> map(lambda x: add(x, 2), [1, 2, 3])
[3, 4, 5]
Carles Sala
  • 1,769
  • 1
  • 15
  • 32
14

If you have it available, I would consider using numpy. It's very fast for these types of operations:

>>> import numpy
>>> numpy.array([1,2,3]) + 2
array([3, 4, 5])

This is assuming your real application is doing mathematical operations (that can be vectorized).

jterrace
  • 57,555
  • 21
  • 140
  • 184
11

If you really really need to use map function (like my class assignment here...), you could use a wrapper function with 1 argument, passing the rest to the original one in its body; i.e. :

extraArguments = value
def myFunc(arg):
    # call the target function
    return Func(arg, extraArguments)


map(myFunc, itterable)

Dirty & ugly, still does the trick

Todor Minakov
  • 14,867
  • 2
  • 44
  • 49
6

I believe starmap is what you need:

from itertools import starmap


def test(x, y, z):
    return x + y + z

list(starmap(test, [(1, 2, 3), (4, 5, 6)]))
Shqi.Yang
  • 191
  • 2
  • 5
2
def func(a, b, c, d):
 return a + b * c % d
map(lambda x: func(*x), [[1,2,3,4], [5,6,7,8]])

By wrapping the function call with a lambda and using the star unpack, you can do map with arbitrary number of arguments.

vpz
  • 736
  • 1
  • 9
  • 22
Yuukio
  • 139
  • 1
  • 4
1

To pass multiple arguments to a map function.

def q(x,y):
    return x*y

print map (q,range(0,10),range(10,20))

Here q is function with multiple argument that map() calls. Make sure, the length of both the ranges i.e.

len (range(a,a')) and len (range(b,b')) are equal.
SeasonalShot
  • 1,558
  • 24
  • 43
1

In :nums = [1, 2, 3]

In :map(add, nums, [2]*len(nums))

Out:[3, 4, 5]

Harsha Biyani
  • 5,322
  • 7
  • 32
  • 48
bzd111
  • 97
  • 4
  • 1
    This does not provide an answer to the question. You can [search for similar questions](https://stackoverflow.com/search), or refer to the related and linked questions on the right-hand side of the page to find an answer. If you have a related but different question, [ask a new question](https://stackoverflow.com/questions/ask), and include a link to this one to help provide context. See: [Ask questions, get answers, no distractions](https://stackoverflow.com/tour) – Tim Diekmann May 23 '18 at 09:41
1

You can include lambda along with map:

list(map(lambda a: a+2, [1, 2, 3]))
Harshal Parekh
  • 4,830
  • 4
  • 13
  • 34
0

Another option is:

results = []
for x in [1,2,3]:
    z = add(x,2)
    ...
    results += [f(z,x,y)]

This format is very useful when calling multiple functions.

andrew-e
  • 654
  • 7
  • 9
0
#multi argument

def joke(r):
     if len(r)==2:
          x, y = r
          return x + y
     elif len(r)==3:
           x,y,z=r
           return x+y+z

#using map

    print(list(map(joke,[[2,3],[3,4,5]])))

output = [6,12]

if the case like above and just want use function

def add(x,y):
    ar =[]
    for xx in x:
         ar.append(xx+y)
    return ar
print(list(map(add,[[3,2,4]],[2]))[0])
output = [5,4,6]

Note: you can modified as you want.