Python: attempt to collapse function mapping by second argument

NOTE. Before commenting, read the BETTER UPDATE section below. There is some subtlety here. As far as I can tell, none of the answers above work in context.

I am trying to find an analog of the python map function with slightly different functionality. This is best explained by example. The map function performs the following actions:

In [1]: def f(x,y): return x+y In [2]: map(f, ['a','b','c'],['1','2','3']) Out[2]: ['a1', 'b2', 'c3'] 

So, the map turns f into a new function, let's call it f_zipper. f_zipper smooths its arguments and applies f to each archived pair.

What I would like to build is a function that I will call "magical_map", which behaves as follows:

 In [1]: def f(x,y): return x+y In [2]: magical_map(f, ['a','b','c'],'1') Out[2]: ['a1', 'b1', 'c1'] 

So magical_map creates a bunch of calls to f (one for each item in the first argument list), but it collapses them all into the second argument.

Note. I need a really functional solution, so to speak, because I will not have access to the second argument.

i.e. what I'm going to do later, the following function is built:

 intermed_func = functools.partial(magical_map, f) final_func = functools.partial(intermed_func, arg_I_know) 

then final_func can be called

 final_func(last_min_arg) 

and return

 [f(arg_I_know[0], last_min_arg), f(arg_I_know[1], last_min_arg), ...] 

I am mostly obsessed with how to create a magical_map. Any help would be great. I was not lucky to find anything on this subject.

Thanks!

BEST UPDATE:

Solving a problem in context is much more complicated than just writing a function that works when both arguments are known at once. The problem is that they are not known in this context. More precisely, I need to do the following "final_func" apply split to all three lines. Right now, using "map", you get the following behavior.

 def splitfunc(string, arg): return string.split(arg) intermed_func = functools.partial(map, splitfunc) final_func = functools.partial(intermed_func, ["a_b","v_c","g,g"]) final_func("_") Out[xx]: [['a', 'b'], ['v_c'], ['g,g']] 

but when I define magical_map as suggested (by all means below), I get either errors or wrong behavior. For instance.

 def magical_map(func, mylist, arg): return map(f, mylist, [arg]*len(mylist)) 

then I run:

 intermed_func = functools.partial(magical_map, splitfunc) final_func = functools.partial(intermed_func, ["a_b","v,c","g,g"]) final_func("_") 

I get:

 ['a_b_', 'v,c_', 'g,g_'] 
+4
source share
5 answers

How about this lazy version:

 >>> def add(x,y): ... return x+y ... >>> def magic_map(func,*args): ... return itertools.starmap(func,itertools.izip(*args)) #just zip in python 3. ... >>> list(magic_map(add,['a', 'b', 'c'], itertools.repeat('1'))) ['a1', 'b1', 'c1'] 

Note that we require zip occupy the shorter of the two rows, so that we can pass infinite iterability to any argument that allows us to extend one with itertools.repeat . This is also evaluated lazily, so I suggest that you could even pass 2 infinite iterations, and that would work fine - if you are not trying to actually iterate over the entire returned object; -)


Here is an attempt to use this in a context similar to what you are doing (although I do not quite understand what you are doing, so this may not be the case):

 import itertools import functools def magic_map(func,*args): return itertools.starmap(func,itertools.izip(*args)) #just zip in python 3. lst = ["a_b","v_c","g,g"] print list(magic_map(str.split, lst, itertools.repeat('_'))) intermed_func = functools.partial(magic_map,str.split) print list(intermed_func(lst ,itertools.repeat('_'))) final_func = functools.partial(intermed_func,lst) print list(final_func(itertools.repeat('_'))) 

Output:

 [['a', 'b'], ['v', 'c'], ['g,g']] [['a', 'b'], ['v', 'c'], ['g,g']] [['a', 'b'], ['v', 'c'], ['g,g']] 

what you want (i think).

+7
source

In Python 3:

As usual, itertools for rescue :

 >>> import itertools >>> list(map(f, ['a','b','c'], itertools.repeat("1"))) ['a1', 'b1', 'c1'] 

For more than one value, use itertools.cycle()

 >>> list(map(f, ['a','b','c','d'], itertools.cycle("12"))) ['a1', 'b2', 'c1', 'd2'] 
+6
source

Use itertools.repeat .

 def magic_map(f, l, v): return map(f, l, itertools.repeat(v, len(l)) 

Use it as follows:

 >>> magic_map(f, ['a', 'b', 'c'], '1') ['a1', 'b1', 'c1'] 

Edit:

map , as thg435 points out , goes until the completion of the longer argument.

+4
source

How about this?

 def magical_map(func, list, arg): return map(func, list, [arg]*len(list)) 

Actually, since a single-line function can also just write it, and not define it separately.

+2
source

What about

 from functools import partial def map_with(f, it, **kwargs): return map(partial(f, **kwargs), it) def f(x,y): return x+y print map_with(f, ['a', 'b', 'c'], y='1') # ['a1', 'b1', 'c1'] 
+2
source

All Articles