Python中Haskell的zipWith函数的类比是什么?
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
答案 0 :(得分:49)
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])]
答案 1 :(得分:38)
如果您愿意,可以创建自己的,但在Python中我们主要做
list_c = [ f(a,b) for (a,b) in zip(list_a,list_b) ]
因为Python本身并不具备功能。它恰好支持一些方便的习语。
答案 2 :(得分:10)
您可以使用地图:
>>> x = [1,2,3,4]
>>> y = [4,3,2,1]
>>> map(lambda a, b: a**b, x, y)
[1, 8, 9, 4]
答案 3 :(得分:6)
使用itertools的懒惰zipWith
:
import itertools
def zip_with(f, *coll):
return itertools.starmap(f, itertools.izip(*coll))
此版本将zipWith
的行为概括为任意数量的迭代。
答案 4 :(得分:4)
一般情况下,正如其他人所说,map和zip可以帮助你像在Haskel中一样复制zipWith的功能。
通常,您可以在两个列表中应用已定义的二元运算符或某个二元函数。使用Python的map / zip替换Haskel 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]
>>>
还有zipWith的其他变体,即zipWith3,zipWith4 .... zipWith7。要复制这些功能主义者,您可能需要使用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]
如您所见,您可以操作任意数量的列表,但您仍然可以使用相同的程序。
答案 5 :(得分:3)
我知道这是一个老问题,但是......
已经说过,典型的python方式就像是
active
因此在代码中看到类似的行,大多数pythonistas都会理解。
还有(我认为)纯粹懒惰的例子:
results = [f(a, b) for a, b in zip(list1, list2)]
但是我相信starmap返回一个迭代器,所以你不能索引,或者多次执行该函数返回的内容。
如果您不是特别关注懒惰和/或需要多次索引或循环浏览新列表,这可能是您可能获得的一般目的:
import itertools
def zipWith(f, *args):
return itertools.starmap(f, itertools.izip(*args))
并不是说您无法使用懒惰版本,但如果您已经建立了列表列表,也可以像这样调用该函数。
def zipWith(func, *lists):
return [func(*args) for args in zip(*lists)]
或者像正常一样:
results = zipWith(func, *lists)
不知何故,该函数调用看起来比列表推导版本更简单,更容易理解。
看着这一点,这看起来奇怪地让人想起我经常写的另一个辅助函数:
results = zipWith(func, list1, list2)
然后可以写成:
def transpose(matrix):
return zip(*matrix)
不是一个更好的版本,但我总觉得有趣的是,当以功能风格编写通用函数时,我经常发现自己会去,"哦。这只是我之前已经写过的函数的一般形式。"