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函数的时候,我经常会发现自己会“哦,这只是我以前写过的一个更通用的函数”。