zip与模拟Python?

Python中Haskell的zipWith函数的模拟是什么?

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] 

如果你愿意的话,你可以创build你自己的,但是在Python中,我们主要是这么做的

 list_c = [ f(a,b) for (a,b) in zip(list_a,list_b) ] 

因为Python本身不具有function。 它只是支持一些便利的习语。

map()

 map(operator.add, [1, 2, 3], [3, 2, 1]) 

虽然通常使用带有zip()的LC。

 [x + y for (x, y) in zip([1, 2, 3], [3, 2, 1])] 

你可以使用地图:

 >>> x = [1,2,3,4] >>> y = [4,3,2,1] >>> map(lambda a, b: a**b, x, y) [1, 8, 9, 4] 

一个懒惰的zipWith itertools:

 import itertools def zip_with(f, *coll): return itertools.starmap(f, itertools.izip(*coll)) 

这个版本概括了zipWith与任意数量的迭代器的行为。

一般来说,正如其他人提到的地图和zip可以帮助您复制zipWith的function,如在Haskel。

一般来说,您可以在两个列表上应用定义的二元运算符或一些二进制函数。以Python的地图/ zipreplaceHaskel zipWith的示例

 Input: zipWith (+) [1,2,3] [3,2,1] Output: [4,4,4] >>> map(operator.add,[1,2,3],[4,3,2]) [5, 5, 5] >>> [operator.add(x,y) for x,y in zip([1,2,3],[4,3,2])] [5, 5, 5] >>> 

还有另外一个zipWith3,zipWith4 …. zipWith7。 要复制这些function主义者,您可能需要使用izip和imap代替zip和map。

 >>> [x for x in itertools.imap(lambda x,y,z:x**2+y**2-z**2,[1,2,3,4],[5,6,7,8],[9,10,11,12])] >>> [x**2+y**2-z**2 for x,y,z in itertools.izip([1,2,3,4],[5,6,7,8],[9,10,11,12])] [-55, -60, -63, -64] 

正如你所看到的,你可以操作任何数量的你想要的列表,你仍然可以使用相同的程序。

我知道这是一个古老的问题,但…

已经有人说,典型的Python方式会是这样的

 results = [f(a, b) for a, b in zip(list1, list2)] 

所以在你的代码中看到这样的一行,大多数pythonistas会理解得很好。

还有一个(我认为)是纯懒惰的例子:

 import itertools def zipWith(f, *args): return itertools.starmap(f, itertools.izip(*args)) 

但是我相信starmap会返回一个迭代器,所以你将无法索引,或者多次执行该函数返回的结果。

如果你不特别关心懒惰和/或需要多次索引或循环遍历你的新列表,这可能是一般的目的,你可以得到:

 def zipWith(func, *lists): return [func(*args) for args in zip(*lists)] 

不是说你不能用懒惰的版本来做,但是如果你已经build立了你的列表清单,你也可以像这样调用这个函数。

 results = zipWith(func, *lists) 

或者像正常一样:

 results = zipWith(func, list1, list2) 

不知何故,该函数调用看起来比列表理解版本更简单,更容易。


看这个,这看起来奇怪的让人联想到另一个我经常写的帮助函数:

 def transpose(matrix): return zip(*matrix) 

然后可以这样写:

 def transpose(matrix): return zipWith(lambda *x: x, *matrix) 

并不是一个更好的版本,但是我总是觉得在编写generics函数的时候,我经常会发现自己会“哦,这只是我以前写过的一个更通用的函数”。