web-dev-qa-db-ja.com

PythonのzipWithアナログ?

PythonのHaskellの zipWith 関数の類似物は何ですか?

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

必要に応じて自分で作成できますが、Python

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

as Pythonは本質的に機能的ではありません。たまたまいくつかの便利なイディオムをサポートしています。

39
dsign

map()

_map(operator.add, [1, 2, 3], [3, 2, 1])
_

LC with Zip()が通常使用されますが。

_[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]
10
heinrich5991

怠惰なzipWithとitertools:

import itertools

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

このバージョンでは、zipWithの動作を任意の数のイテラブルで一般化します。

6
Taurus Olson

一般に他の人がマップについて言及しているように、ZipはHaskelのようにzipWithの機能を複製するのに役立ちます。

一般に、定義された2項演算子または2つのリストにある2項関数のいずれかを適用できます。HaskelzipWithをPythonのmap/Zipで置き換える例

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の他のバリエーションがあります。これらの機能主義者を再現するには、Zipとマップの代わりにizipとimapを使用することができます。

>>> [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] 

ご覧のとおり、必要なリストをいくつでも操作でき、同じ手順を使用できます。

4
Abhijit

これは古い質問であることは知っていますが、...

典型的なpythonの方法は次のようなものになると既に言われています

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

コードにそのような行を表示すると、ほとんどのpythonistaは問題なく理解できます。

また、(私が思うに)純粋に怠惰な例がすでに示されています:

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)]

遅延バージョンではそれができなかったわけではありませんが、リストのリストをすでに作成している場合は、そのようにその関数を呼び出すこともできます。

results = zipWith(func, *lists)

または通常のように:

results = zipWith(func, list1, list2)

どういうわけか、その関数呼び出しは、リスト内包バージョンよりも単純で簡単に理解できます。


これを見ると、これは私がよく書く別のヘルパー関数を奇妙に連想させます。

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

これは次のように書くことができます:

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

それほど優れたバージョンではありませんが、関数型のスタイルでジェネリック関数を書くときに、「ああ。これは、以前に書いた関数のより一般的な形式にすぎない」ということがよくあります。

3
Brad Richardson