4

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

我试图找到一个功能略有不同的python'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']

所以 magic_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”应用于所有三个字符串。现在,使用“地图”会产生以下行为。

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

但是当我按照建议(以下面的所有方式)定义magic_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_']
4

5 回答 5

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

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

于 2012-12-14T18:46:35.670 回答
6

在 Python 3 中:

像往常一样,这是itertools为了救援

>>> 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']
于 2012-12-14T18:35:41.190 回答
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']

编辑:

map,正如thg435 所指出的,一直持续到更长的参数结束。

于 2012-12-14T18:36:43.383 回答
2

这个怎么样?

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

其实既然是单行函数,不如直接写出来,不要单独定义。

于 2012-12-14T18:35:59.800 回答
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']
于 2012-12-14T18:42:19.867 回答