使用python map和其他功能工具

时间:2009-03-23 03:46:29

标签: python dictionary functional-programming

这非常糟糕,但我正在尝试学习/理解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内部向条形图应用另一个过滤器映射?

9 个答案:

答案 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.imapmap()类似,但只要最短的可迭代停止就会停止。

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))