apply vector of functions to vector of arguments
<p>I'd like to take in a list of functions, <code>funclist</code>, and return a new function which takes in a list of arguments, <code>arglist</code>, and applies the <code>i</code>th function in <code>funclist</code> to the <code>i</code>th element of <code>arglist</code>, returning the results in a list:</p>

<pre><code>def myfunc(funclist):
    return lambda arglist: [ funclist[i](elt) for i, elt in enumerate(arglist) ]
</code></pre>

<p>This is not optimized for parallel/vectorized application of the independent functions in <code>funclist</code> to the independent arguments in <code>argvec</code>. Is there a built-in function in python or numpy (or otherwise) that will return a more optimized version of the <code>lambda</code>  above? It would be similar in spirit to <code>map</code> or <code>numpy.vectorize</code> (but obviously not the same), and so far I haven't found anything.</p>

<p>In <code>numpy</code> terms true vectorization means performing the iterative stuff in compiled code.  Usually that requires using <code>numpy</code> functions that work with whole arrays, doing thing like addition and indexing.</p>

<p><code>np.vectorize</code> is a way of iterate of several arrays, and using their elements in a function that does not handle arrays.  It doesn't do much in compiled code, so does not improve the speed much.  It's most valuable as a way of applying <code>numpy</code> broadcasting rules to your own scalar function.</p>

<p><code>map</code> is a variant on list comprehension, and has basically the same speed.  And a list comprehension has more expressive power, working with several lists.</p>

<p><code>@Tore's</code> zipped comprehension is a clear expression this task</p>

<pre><code>[f(args) for f, args in zip(funclist, arglist)]
</code></pre>

<p><code>map</code> can work with several input lists:</p>

<pre><code>In [415]: arglist=[np.arange(3),np.arange(1,4)]
In [416]: fnlist=[np.sum, np.prod]
In [417]: [f(a) for f,a in zip(fnlist, arglist)]
Out[417]: [3, 6]
In [418]: list(map(lambda f,a: f(a), fnlist, arglist))
Out[418]: [3, 6]
</code></pre>

<p>Your version is a little wordier, but functionally the same.</p>

<pre><code>In [423]: def myfunc(funclist):
     ...:     return lambda arglist: [ funclist[i](elt) for i, elt in enumerate(arglist) ]

In [424]: myfunc(fnlist)
Out[424]: &lt;function __main__.myfunc.&lt;locals&gt;.&lt;lambda&gt;&gt;
In [425]: myfunc(fnlist)(arglist)
Out[425]: [3, 6]
</code></pre>

<p>It has the advantage of generating a function that can be applied to different arglists:</p>

<pre><code>In [426]: flist=myfunc(fnlist)
In [427]: flist(arglist)
Out[427]: [3, 6]
In [428]: flist(arglist[::-1])
Out[428]: [6, 0]
</code></pre>

<p>I would have written <code>myfunc</code> more like:</p>

<pre><code>def altfun(funclist):
   def foo(arglist):
       return [f(a) for f,a in zip(funclist, arglist)]
   return foo
</code></pre>

<p>but the differences are just stylistic.</p>

<p>================</p>

<p>Time test for <code>zip</code> v <code>enumerate</code>:</p>

<pre><code>In [154]: funclist=[sum]*N
In [155]: arglist=[list(range(N))]*N
In [156]: sum([funclist[i](args) for i,args in enumerate(arglist)])
Out[156]: 499500000
In [157]: sum([f(args) for f,args in zip(funclist, arglist)])
Out[157]: 499500000

In [158]: timeit [funclist[i](args) for i,args in enumerate(arglist)]
10 loops, best of 3: 43.5 ms per loop

In [159]: timeit [f(args) for f,args in zip(funclist, arglist)]
10 loops, best of 3: 43.1 ms per loop
</code></pre>

<p>Basically the same.  But <code>map</code> is 2x faster</p>

<pre><code>In [161]: timeit list(map(lambda f,a: f(a), funclist, arglist))
10 loops, best of 3: 23.1 ms per loop
</code></pre>

<p>Packaging the iteration in a callable is also faster</p>

<pre><code>In [165]: timeit altfun(funclist)(arglist)
10 loops, best of 3: 23 ms per loop
In [179]: timeit myfunc(funclist)(arglist)
10 loops, best of 3: 22.6 ms per loop
</code></pre>

python numpy vectorization