zipWith Python中的模拟?

Yro*_*irg 49 python haskell

在Python中,Haskell的zipWith函数的类比是什么?

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
Run Code Online (Sandbox Code Playgroud)

Ign*_*ams 51

map()

map(operator.add, [1, 2, 3], [3, 2, 1])
Run Code Online (Sandbox Code Playgroud)

虽然zip()通常使用LC .

[x + y for (x, y) in zip([1, 2, 3], [3, 2, 1])]
Run Code Online (Sandbox Code Playgroud)

  • 注意:当列表的长度不匹配时,与`zipWith`相比,这有不同的行为.Haskell的`zipWith`将输入列表截断为最短的长度,而Python的`map`则传递`None`代替较短列表中缺少的元素.例如,`zipWith(+)[1,2],[3,2,1] == [4,4]`,`而图(operator.add,[1,2],[3,2,1 ])`抛出一个异常,试图添加一个整数和"无". (10认同)
  • @hammar:你在Python 2.x中谈论`map`.Python 3.x中的`map`(以及2.x中的`imap`)在最短列表结束后停止.此外,`zip`在最短列表以2.x和3.x结尾后停止 (6认同)

dsi*_*ign 40

如果您愿意,您可以创建自己的,但在Python中我们主要做

list_c = [ f(a,b) for (a,b) in zip(list_a,list_b) ] 
Run Code Online (Sandbox Code Playgroud)

因为Python本身并不具备功能.它恰好支持一些方便的习语.

  • 如果你想要稍微优雅一点,你可以在zip(list_a,list_b)中使用``[f(*list_c)for list_c]`` - 使用``splat``运算符解包元组而不是说明两次.这样做的另一个好处是,你可以只为zip函数添加更多的参数,如果你需要,它会很愉快地工作. (18认同)
  • 请注意,如果您使用的是Python 2.x,则上面的代码并不是懒惰的:`zip()`将构建一个将使用一次的列表.在Python 2.x中,您可以使用`itertools.izip()`进行延迟评估; 在Python 3中,你使用内置的`zip()`进行惰性求值. (5认同)
  • @steveha,但请注意,即使使用`izip`而不是`zip`,它也不是真正的惰性(最接近的Python必须具有Haskell意义),因为它是作为列表理解而不是生成器表达式给出的。 (2认同)
  • @steveha 你说的是 2.x 中的“上面的代码并不懒惰”。它在 3.x 中也不懒惰:它会立即生成整个输出列表。在 3.x 中,它不会*也*为 `zip` 的输出构造一个中间值,所以从这个意义上说,可能会有更多的懒惰,但*代码作为一个整体* 不是懒惰的,无论哪个您正在使用的 Python 版本。为此,正如@lvc 所说,您需要一个生成器表达式。(以及`izip` 以避免在访问第一项时具体化整个中间列表。) (2认同)

hei*_*991 10

你可以使用map:

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


Tau*_*son 6

一个懒惰zipWith的itertools:

import itertools

def zip_with(f, *coll):
    return itertools.starmap(f, itertools.izip(*coll))
Run Code Online (Sandbox Code Playgroud)

此版本概括了zipWith任意数量的iterables 的行为.