2つのリストを並行して反復処理するには?

Pythonには2つのイテレータブルがありますが、それをペアで見ていきたいと思います。

foo = (1, 2, 3)
bar = (4, 5, 6)

for (f, b) in some_iterator(foo, bar):
    print "f: ", f, "; b: ", b

という結果になるはずです。

f: 1; b: 4
f: 2; b: 5
f: 3; b: 6

*1つの方法は、インデックスを反復することです。

for i in xrange(len(foo)):
    print "f: ", foo[i], "; b: ", b[i]

しかし、これは私にはやや不自然に思えます。もっと良い方法はありますか?

ソリューション

Python 3

for f, b in zip(foo, bar):
    print(f, b)

zipfoo または bar の短い方が停止すると停止します。

Python 3**では、 zip は Python2 の itertools.izip のようにタプルのイテレータを返します。 タプルのリストを取得するには タプルのリストを得るには、list(zip(foo, bar))を使います。そして、両方のイテレータがなくなるまで zip を実行するには また、両方のイテレータがなくなるまで zip を実行するには、次のようにします。 itertools.zip_longestを使用します。

Python 2

Python 2**では、zip はタプルのリストを返します。これは foobar が巨大でない場合には良いことです。両者が巨大な場合、 zip(foo,bar) を形成することは不必要に巨大な一時変数であり 一時的な変数であり、 itertools.izipitertools.izip_ で置き換える必要があります。 これはリストではなくイテレータを返します。

import itertools
for f,b in itertools.izip(foo,bar):
    print(f,b)
for f,b in itertools.izip_longest(foo,bar):
    print(f,b)

izipfoo または bar のどちらかが枯渇したときに停止します。 izip_longestfoobar の両方が使い果たされたときに停止します。 短い方のイテレータを使い切ると、izip_longest はそのイテレータに対応する位置に None を持つタプルを生成します。必要に応じて、None以外の別のfillvalueを設定することもできます。詳しい話]1はこちらをご覧ください。


また、zipとそのzip的なものは、任意の数のイテレートを引数として受け入れることができることに注意してください。たとえば、以下のようになります。

for num, cheese, color in zip([1,2,3], ['manchego', 'stilton', 'brie'], 
                              ['red', 'blue', 'green']):
    print('{} {} {}'.format(num, color, cheese))

プリント

1 red manchego
2 blue stilton
3 green brie
解説 (9)

zip」機能が欲しい。

for (f,b) in zip(foo, bar):
    print "f: ", f ,"; b: ", b
解説 (1)

zip]1'関数を使用する必要があります。以下は、独自のZIP関数の例です。

def custom_zip(seq1, seq2):
    it1 = iter(seq1)
    it2 = iter(seq2)
    while True:
        yield next(it1), next(it2)
解説 (2)