Using python map and other functional tools
这是非常不流行的,但我正在尝试学习/理解Python中的函数式编程。以下代码:
1 2 3 4 5 6 7 | foos = [1.0,2.0,3.0,4.0,5.0] bars = [1,2,3] def maptest(foo, bar): print foo, bar map(maptest, foos, bars) |
生产:
1 2 3 4 5 | 1.0 1 2.0 2 3.0 3 4.0 None 5.0 None |
问:有没有一种方法可以在python中使用map或任何其他功能工具来生成以下内容,而不使用循环等。
1 2 3 4 5 | 1.0 [1,2,3] 2.0 [1,2,3] 3.0 [1,2,3] 4.0 [1,2,3] 5.0 [1,2,3] |
正如附带说明的那样,如果foo和bar之间存在依赖关系,实现将如何更改。例如
1 2 | foos = [1.0,2.0,3.0,4.0,5.0] bars = [1,2,3,4,5] |
打印:
1 2 3 4 | 1.0 [2,3,4,5] 2.0 [1,3,4,5] 3.0 [1,2,4,5] ... |
P.S:我知道如何简单地使用if、循环和/或生成器来实现它,但是我想学习如何使用功能性工具来实现相同的目标。这只是将if语句添加到maptest还是将另一个过滤器映射应用到maptest内部的条的一种情况?
你熟悉其他的功能语言吗?例如,您是想学习Python是如何进行函数式编程的,还是想学习函数式编程并将Python作为工具?
另外,你明白清单的理解吗?
1 | map(f, sequence) |
直接等同于:
1 | [f(x) for x in sequence] |
事实上,我认为
1 | map(f, sequence1, sequence2) |
主要相当于:
1 | [f(x1, x2) for x1, x2 in zip(sequence1, sequence2)] |
(在处理序列长度不同的情况时,它有不同的处理方式。如您所见,当一个序列用完时,
因此,为了解决您的特定问题,您尝试产生以下结果:
1 2 3 4 | foos[0], bars foos[1], bars foos[2], bars # etc. |
您可以通过编写一个函数来实现这一点,该函数接受一个参数并将其打印出来,然后是条形图:
1 2 3 | def maptest(x): print x, bars map(maptest, foos) |
或者,您可以创建一个如下所示的列表:
1 | [bars, bars, bars, ] # etc. |
并使用原始地图测试:
1 2 | def maptest(x, y): print x, y |
这样做的一种方法是事先明确地构建列表:
1 2 | barses = [bars] * len(foos) map(maptest, foos, barses) |
或者,您可以拉入
1 | map(maptest, foos, itertools.repeat(bars)) |
你将得到无限的输出,因为只要其中一个参数仍在产生输出,
1 | itertools.imap(maptest, foos, itertools.repeat(bars)) |
希望这有帮助:—)
(*)在Python3.0中有点不同。在这里,map()基本上返回一个生成器表达式。
最简单的方法不是通过不同的函数传递
1 2 3 4 5 6 7 | foos = [1.0,2.0,3.0,4.0,5.0] bars = [1,2,3] def maptest(foo): print foo, bars map(maptest, foos) |
使用您原来的
1 | map((lambda foo: maptest(foo, bars)), foos) |
下面是您要寻找的解决方案:
1 2 3 4 5 | >>> foos = [1.0, 2.0, 3.0, 4.0, 5.0] >>> bars = [1, 2, 3] >>> [(x, bars) for x in foos] [(1.0, [1, 2, 3]), (2.0, [1, 2, 3]), (3.0, [1, 2, 3]), (4.0, [1, 2, 3]), (5.0, [ 1, 2, 3])] |
我建议使用列表理解(
1 2 3 4 5 6 7 8 9 | >>> y = ((x, bars) for x in foos) >>> for z in y: ... print z ... (1.0, [1, 2, 3]) (2.0, [1, 2, 3]) (3.0, [1, 2, 3]) (4.0, [1, 2, 3]) (5.0, [1, 2, 3]) |
不同的是,生成器理解被延迟加载。
更新以响应此评论:
Of course you know, that you don't copy bars, all entries are the same bars list. So if you modify any one of them (including original bars), you modify all of them.
我想这是一个正确的观点。我可以想到两种解决办法。最有效的方法可能是这样的:
1 2 | tbars = tuple(bars) [(x, tbars) for x in foos] |
由于元组是不可变的,这将防止通过列表理解的结果修改条(或者,如果您执行该路径,则可以修改生成器理解)。如果确实需要修改每个结果,可以这样做:
1 2 | from copy import copy [(x, copy(bars)) for x in foos] |
但是,这在内存使用和速度方面都有点昂贵,所以我建议您不要这样做,除非您真的需要添加到它们中的每一个中。
函数式编程是关于创建无副作用的代码。
映射是一个功能列表转换抽象。你用它来获取某物的序列,然后把它转换成其他某物的序列。
您试图将其用作迭代器。别那么做。:)
下面是一个如何使用map构建所需列表的示例。有较短的解决方案(我只使用理解),但这将有助于您更好地了解地图的功能:
1 2 3 4 | def my_transform_function(input): return [input, [1, 2, 3]] new_list = map(my_transform, input_list) |
注意,此时,您只进行了数据操作。现在可以打印:
1 2 | for n,l in new_list: print n, ll |
--我不知道"without loops"是什么意思。fp并不是为了避免循环(如果不访问每个循环,就不能检查列表中的每个项目)。这是为了避免副作用,从而减少写错误。
1 2 3 4 5 6 7 8 9 | >>> from itertools import repeat >>> for foo, bars in zip(foos, repeat(bars)): ... print foo, bars ... 1.0 [1, 2, 3] 2.0 [1, 2, 3] 3.0 [1, 2, 3] 4.0 [1, 2, 3] 5.0 [1, 2, 3] |
1 2 3 4 5 6 | import itertools foos=[1.0, 2.0, 3.0, 4.0, 5.0] bars=[1, 2, 3] print zip(foos, itertools.cycle([bars])) |
下面是
function 是您的函数名。sequences 是任何数量的序列,通常是列表或元组。map 将同时对其进行迭代,并将当前值提供给function 。这就是为什么序列数应该等于函数的参数数。
听起来像是在迭代
像其他人建议的那样,使用全局变量或列表理解之类的变通方法。
这个怎么样?
1 2 3 4 5 6 7 | foos = [1.0,2.0,3.0,4.0,5.0] bars = [1,2,3] def maptest(foo, bar): print foo, bar map(maptest, foos, [bars]*len(foos)) |
这样可以吗?
1 2 3 4 5 6 7 8 9 10 11 | foos = [1.0,2.0,3.0,4.0,5.0] bars = [1,2,3] def maptest2(bar): print bar def maptest(foo): print foo map(maptest2, bars) map(maptest, foos) |