使用Python映射和其他function工具
这是相当不错的,但我正在学习/理解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
问:有没有办法使用地图或任何其他function的工具在Python中产生以下没有循环等
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之间存在依赖关系,实现将如何更改。 例如
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] ...
PS:我知道如何天真地使用if,loops和/或generator,但我想学习如何使用function工具来实现相同的function。 是否只是添加一个if语句来maptesttesting或在maptest内部应用另一个filter贴图的情况?
最简单的方法是不通过不同的function,而是直接从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)
你熟悉其他function语言吗? 即你想学习如何python做function编程,或者你想了解function编程和使用python作为车辆?
另外,你是否理解列表parsing?
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)
或者,您可以创build一个如下所示的列表:
[bars, bars, bars, ] # etc.
并使用您的原始maptest:
def maptest(x, y): print x, y
一种方法是预先明确地build立列表:
barses = [bars] * len(foos) map(maptest, foos, barses)
或者,你可以拉动itertools
模块。 itertools
包含许多巧妙的function,可以帮助你在python中进行函数式的懒惰评估编程。 在这种情况下,我们需要itertools.repeat
,在迭代它时将无限期地输出它的参数。 这最后一个事实意味着如果你这样做:
map(maptest, foos, itertools.repeat(bars))
你将得到无尽的输出,因为只要其中一个参数仍然产生输出, map()
一直持续下去。 但是, itertools.imap
就像map()
,但是一旦最短迭代停止,就停止。
itertools.imap(maptest, foos, itertools.repeat(bars))
希望这可以帮助 :-)
(*)在Python 3.0中有点不同。 在那里,map()基本上返回一个生成器expression式。
这是您正在寻找的解决scheme:
>>> 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])]
我build议在使用map的时候使用list comprehension( [(x, bars) for x in foos]
的[(x, bars) for x in foos]
部分),因为它避免了每次迭代(这可能是非常重要的)函数调用的开销。 如果你只是在for循环中使用它,你可以通过使用generator生成器来获得更好的速度:
>>> 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])
不同之处在于生成器的理解是延迟加载的 。
更新为了回应这个评论:
当然,你知道,你不复制栏,所有条目都是同样的栏列表。 所以如果你修改它们中的任何一个(包括原始的条),你修改它们。
我想这是一个有效的观点。 有两个解决scheme,我可以想到。 效率最高的可能是这样的:
tbars = tuple(bars) [(x, tbars) for x in foos]
因为元组是不可变的,所以这将防止通过这个列表理解的结果(或者如果你去那个路由发生器理解的话)修改它们。 如果你真的需要修改每一个结果,你可以这样做:
from copy import copy [(x, copy(bars)) for x in foos]
然而,这在内存使用和速度方面都可能有点贵,所以我build议不要这样做,除非你真的需要添加到其中每一个。
函数式编程是关于创build无副作用的代码。
map是一个function列表转换抽象。 你用它来取一些东西,把它变成一系列别的东西。
你正试图用它作为迭代器。 不要这样做。 🙂
下面是一个如何使用map来构build你想要的列表的例子。 有更短的解决scheme(我只是使用理解),但这将帮助您了解什么地图做得更好一点:
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不是关于避免循环(你不能检查列表中的每个项目,而不访问每个项目)。 这是为了避免副作用,从而写出更less的错误。
>>> 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]
import itertools foos=[1.0, 2.0, 3.0, 4.0, 5.0] bars=[1, 2, 3] print zip(foos, itertools.cycle([bars]))
下面是map(function, *sequences)
函数的参数概述:
-
function
是你的函数的名字。 -
sequences
是任何数量的序列,通常是列表或元组。map
将同时迭代它们并给出当前值的function
。 这就是为什么序列的数量应该等于你的函数的参数数量。
这听起来像你试图迭代一些function
的参数,但保持其他人不变,不幸的是map
不支持。 我发现了一个旧的build议 ,将这样的function添加到Python,但是地图结构非常干净和完善,我怀疑这样的function是否会被实现。
像其他人所build议的那样,使用像全局variables或列表parsing这样的解决方法。
这会做吗?
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)
这个怎么样:
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))