Python:尝试在第二个参数上折叠函数映射

时间:2012-12-14 18:32:53

标签: python functional-programming

注意:请在评论前阅读下面的更新部分。这里有一些微妙之处。据我所知,所有答案都没有在上下文中起作用。

我正试图找到一个模拟python'map'功能,功能略有不同。最好用例子来解释。 'map'功能执行以下操作:

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

Out[2]:    ['a1', 'b2', 'c3']

因此,map将f转换为新函数,我们称之为f_zipper。 f_zipper压缩其参数并将f应用于每个压缩对。

我想要构建的是一个我称之为'magical_map'的函数,其行为如下:

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

Out[2]:    ['a1', 'b1', 'c1']

因此,magical_map会对f进行一系列调用(第一个参数列表中的每个元素都有一个),但它会将它们全部折叠到第二个参数上。

注意:我需要一个真正有效的解决方案,可以这么说,因为我无法访问第二个参数。

即。我稍后要做的是建立以下功能:

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

然后可以将final_func称为

final_func(last_min_arg)

并返回

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

我基本上对如何构建'magical_map'感到困惑。任何帮助都会很棒。我在这个问题上找不到任何好运。

谢谢!

更新更新:

在上下文中解决问题比编写一个在两个参数一次都知道时有效的函数要困难得多。问题是,在这种情况下,它们并不为人所知。更确切地说,我需要能够将以下'final_func'应用拆分为所有三个字符串。现在,使用'map'会产生以下行为。

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']]

但是当我按照建议定义magical_map时(以下各方面)我得到错误或不正确的行为。例如。

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

然后我跑:

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

final_func("_")

我明白了:

['a_b_', 'v,c_', 'g,g_']

5 个答案:

答案 0 :(得分:7)

这个懒惰的版本怎么样:

>>> 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']

请注意,我们要求zip取两个系列中较短的一个,以便我们可以将无限迭代传递给任一参数,这允许我们使用itertools.repeat扩展一个。这也是懒惰的评估,所以我想你甚至可以通过2个无限的迭代,它可以正常工作 - 如果你没有尝试实际迭代整个返回的对象; - )


这是尝试在类似于你正在做的事情中使用它(尽管我不完全理解你在做什么,所以这可能会有所不同):

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('_')))

输出是:

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

这就是你想要的(我想)。

答案 1 :(得分:6)

在Python 3中:

像往常一样,它是itertools to the rescue

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

对于多个值,请使用itertools.cycle()

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

答案 2 :(得分:4)

使用itertools.repeat

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

像这样使用:

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

修改

正如thg435指出的那样,

map一直持续到较长的论证结束。

答案 3 :(得分:2)

这个怎么样?

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

实际上,既然这是一个单行函数,也可以把它写出来而不是单独定义它。

答案 4 :(得分:2)

怎么样

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']