这非常糟糕,但我正在尝试学习/理解python中的函数式编程。以下代码:
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.0 1
2.0 2
3.0 3
4.0 None
5.0 None
问。有没有办法在python中使用map或任何其他功能工具来生成以下没有循环等。
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之间存在依赖关系,实现将如何变化。 e.g。
foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3,4,5]
并打印:
1.0 [2,3,4,5]
2.0 [1,3,4,5]
3.0 [1,2,4,5]
...
P.S:我知道如何使用if,循环和/或生成器来天真地做,但我想学习如何使用功能工具实现相同的功能。是否只是在maptest中添加if语句或在maptest内部向条形图应用另一个过滤器映射?
答案 0 :(得分:194)
您熟悉其他功能语言吗?即你是在尝试学习python如何进行函数式编程,还是在尝试学习函数式编程并使用python作为载体?
另外,你了解列表理解吗?
map(f, sequence)
直接等同于(*)到:
[f(x) for x in sequence]
事实上,我认为map()
曾经被定为从python 3.0中删除,因为它是多余的(没有发生)。
map(f, sequence1, sequence2)
大致相当于:
[f(x1, x2) for x1, x2 in zip(sequence1, sequence2)]
(它处理序列长度不同的情况有所不同。如您所见,map()
在其中一个序列用完时填充None,而zip()
在最短的序列停止)
因此,为了解决您的具体问题,您正试图产生结果:
foos[0], bars
foos[1], bars
foos[2], bars
# etc.
你可以通过编写一个带有单个参数并打印它的函数来做到这一点,然后是条形码:
def maptest(x):
print x, bars
map(maptest, foos)
或者,您可以创建一个如下所示的列表:
[bars, bars, bars, ] # etc.
并使用您原来的maptest:
def maptest(x, y):
print x, y
执行此操作的一种方法是预先明确地构建列表:
barses = [bars] * len(foos)
map(maptest, foos, barses)
或者,您可以拉入itertools
模块。 itertools
包含许多聪明的函数,可以帮助您在python中进行函数式的惰性求值编程。在这种情况下,我们需要itertools.repeat
,当您迭代它时,它将无限期地输出其参数。最后一个事实意味着,如果你这样做:
map(maptest, foos, itertools.repeat(bars))
你将得到无穷无尽的输出,因为map()
只要其中一个参数仍然产生输出就会继续。但是,itertools.imap
与map()
类似,但只要最短的可迭代停止就会停止。
itertools.imap(maptest, foos, itertools.repeat(bars))
希望这会有所帮助: - )
(*)在python 3.0中有点不同。在那里,map()基本上返回一个生成器表达式。
答案 1 :(得分:55)
最简单的方法是不通过bars
通过不同的功能,而是直接从maptest
访问它:
foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3]
def maptest(foo):
print foo, bars
map(maptest, foos)
使用原始maptest
函数,您还可以在map
中使用lambda函数:
map((lambda foo: maptest(foo, bars)), foos)
答案 2 :(得分:30)
以下是您正在寻找的解决方案:
>>> 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])]
我建议使用列表推导([(x, bars) for x in foos]
部分)而不是使用map,因为它避免了每次迭代时函数调用的开销(这可能非常重要)。如果你只是想在for循环中使用它,你将通过使用生成器理解获得更好的速度:
>>> 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])
不同之处在于生成器理解是lazily loaded。
更新回复此评论:
当然你知道,你没有复制条,所有条目都是相同的条形列表。因此,如果您修改其中任何一个(包括原始栏),则修改所有这些。
我认为这是一个有效的观点。我能想到有两种解决方案。效率最高的可能是这样的:
tbars = tuple(bars)
[(x, tbars) for x in foos]
由于元组是不可变的,这将阻止通过此列表理解的结果修改条形(或者如果你去那条路线则生成器理解)。如果您确实需要修改每个结果,可以执行以下操作:
from copy import copy
[(x, copy(bars)) for x in foos]
然而,就内存使用和速度而言,这可能有点贵,所以除非你真的需要添加它们,否则我建议不要这样做。
答案 3 :(得分:20)
功能编程是关于创建无副作用的代码。
map是一个功能列表转换抽象。你用它来取一些东西然后把它变成一个别的序列。
您正在尝试将其用作迭代器。不要那样做。 :)
以下是如何使用map构建所需列表的示例。有更短的解决方案(我只是使用理解),但这将有助于您了解哪些地图做得更好:
def my_transform_function(input):
return [input, [1, 2, 3]]
new_list = map(my_transform, input_list)
请注意,此时您只进行了数据操作。现在你可以打印出来了:
for n,l in new_list:
print n, ll
- 我不确定你的意思是'没有循环'。 fp不是关于避免循环(你不能检查列表中的每个项目而不访问每个项目)。这是为了避免副作用,从而减少错误。
答案 4 :(得分:12)
>>> 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]
答案 5 :(得分:11)
import itertools
foos=[1.0, 2.0, 3.0, 4.0, 5.0]
bars=[1, 2, 3]
print zip(foos, itertools.cycle([bars]))
答案 6 :(得分:6)
以下是map(function, *sequences)
函数的参数概述:
function
是您的功能名称。sequences
是任意数量的序列,通常是列表或元组。 map
将同时迭代 并将当前值提供给function
。这就是为什么序列的数量应该等于函数的参数数量。听起来你正试图迭代一些function
的参数,但保持其他参数不变,不幸的是map
不支持这一点。我发现an old proposal要为Python添加这样一个功能,但是地图构造是如此干净和完善,我怀疑这样的东西是否会被实现。
像其他人所建议的那样,使用全局变量或列表推导等变通方法。
答案 7 :(得分:0)
会这样做吗?
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)
答案 8 :(得分:0)
这个怎么样:
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))