Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: trying to collapse a function mapping on the second argument

NOTE: Please read the BETTER UPDATE section below before commenting. There is some subtlety here. None of the answers given yet work in context, as far as I can tell.

I'm trying to find an analog to the python 'map' function with slightly different functionality. This is best explained by example. The 'map' function does the following:

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, map turns f into a new function, let's call it f_zipper. f_zipper zips its arguments and applies f to each zipped pair.

What I'd like to build is a function that I'll call 'magical_map' that 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 makes a bunch of calls to f (one for each element in the first argument list), but it collapses them all onto the second argument.

Note: I need a truly functional solution, so to speak, because I won't have access to the second argument.

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

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

then final_func can be called as

final_func(last_min_arg)

and return

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

I'm basically stumped on how to build 'magical_map'. Any help would be great. I haven't had a lot of luck finding anything on this subject.

Thanks!

BETTER UPDATE:

Solving the problem in context is much harder than simply writing a function that works when both arguments are known at once. The problem is, they are not known in this context. More precisely, I need to be able to make the following 'final_func' apply split to all three strings. Right now, using 'map' gives 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 (in all ways below) I get either errors or incorrect behavior. For example.

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_']
like image 984
user1904822 Avatar asked Nov 30 '22 13:11

user1904822


1 Answers

What 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 the zip to take the shorter of the two series so that we can pass an infinite iterable to either argument which allows us to expand one using itertools.repeat. This evaluates lazily as well, so I suppose that you could even pass 2 infinite iterables and it would work OK -- Provided you don't try to actually iterate over the entire returned object ;-)


Here's an attempt to use this in a context similar to what you're doing (although I don't completely understand what you're doing, so this could be way off):

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 is:

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

which is what you want (I think).

like image 186
mgilson Avatar answered Dec 05 '22 05:12

mgilson