zip()関数はPython 2で登場しました(当時はリストを返していました)が、Python 3では遅延イテレータを返します。これは、複数のシーケンスを要素ごとに組み合わせることができ、並行して反復可能なコレクションを処理するのに便利かつ効率的です。
複数のリスト(または他のタイプのシーケンス)を同時に処理する必要があることがよくあります。例えば、キーと値のペアや、点とペアの座標を処理する場合です。インデックスの手動同期はエラーと可読性の低下を引き起こす原因となります。特に異なる長さのコレクションの場合はなおさらです。
zip()関数は任意の数の反復可能なオブジェクトを受け取り、各反復可能なオブジェクトから対応する要素を含むタプルのイテレータを返します。長さが異なるシーケンスの場合、結果は最も短いシーケンスで切り捨てられます。
names = ['Alice', 'Bob', 'Charlie'] ages = [24, 27, 30] for name, age in zip(names, ages): print(f'{name}は{age}歳です')
zipは*を使って展開できます:
pairs = [(1, 'a'), (2, 'b'), (3, 'c')] nums, chars = zip(*pairs) print(nums) # (1, 2, 3) print(chars) # ('a', 'b', 'c')
異なる長さのコレクションをzip()に渡すとどうなりますか?
zip()は最も短いコレクションの終わりに達すると停止します — 長いコレクションの残りの要素は無視されます。
print(list(zip([1,2,3], ['a','b']))) # [(1, 'a'), (2, 'b')]
デフォルト値で短いシーケンスを補完するタプルを取得するにはどうすればよいですか?
標準のzip()ではこれを行えませんが、そのような動作をするitertools.zip_longestがあります:
from itertools import zip_longest for a, b in zip_longest([1,2], ['x','y','z'], fillvalue=None): print(a, b) # 1 x # 2 y # None z
zip()の結果を「アンパック」して元のリストを再取得できますか?
はい、すべての元のコレクションの長さが同じであり、結果が変更されていない場合は、*演算子を使用してzipを展開できます。
pairs = [(1,2), (3,4)] a, b = zip(*pairs) print(a) # (1, 3) print(b) # (2, 4)
異なる長さのリンクされたコレクションをzipの特性を考慮せずに処理:
lst1 = [1,2,3,4] lst2 = ['a','b'] for x, y in zip(lst1, lst2): print(x, y) # 1 a # 2 b # (3,4)および'lst1'の'c'、'd'は処理されていません
利点:
欠点:
fillvalueを使用してzip_longestを使用し、いかなる要素も失わないようにします:
from itertools import zip_longest lst1 = [1,2,3,4] lst2 = ['a','b'] for x, y in zip_longest(lst1, lst2, fillvalue='?'): print(x, y) # 1 a # 2 b # 3 ? # 4 ?
利点:
欠点: