Python zip関数を徹底解説!複数のリストを同時にループ処理するエレガントな方法
こんにちは。ゆうせいです。
プログラミングをしていると、「2つのリストがあって、それぞれの同じ番目の要素をペアにして処理したいな…」なんて思うことはありませんか?
例えば、生徒の名前がリストになったものと、その生徒たちのテストの点数がリストになったものがあるとします。
names = ['佐藤', '鈴木', '高橋']
scores = [90, 85, 95]
この「佐藤さん」と「90点」、「鈴木さん」と「85点」…というペアを、順番に取り出して処理したい時、あなたならどう書きますか?
もしかしたら、こんな風にインデックス(要素の番号)を使ったループを思いつくかもしれません。
for i in range(len(names)):
name = names[i]
score = scores[i]
print(f'{name}さんの点数は{score}点です。')
確かにこの方法でも正しく動きます。でも、もう少しスッキリと、いかにもPythonらしい書き方ができたら、もっとコードが読みやすくなると思いませんか?
そんな時に絶大な効果を発揮するのが、今回ご紹介するzip()
関数です!
zip関数とは、一体なに?
zip()
関数は、その名の通り、まるで**洋服のジッパー(zipper)**のように、複数のリスト(やタプルなどの繰り返し可能なデータ)を「ガチャン!」と噛み合わせて、ひとまとめにしてくれる関数です。
ジッパーが左右の歯を一つずつ噛み合わせて閉まっていくように、zip()
関数は、渡された複数のリストの同じ順番の要素同士をペアにして、次々と取り出せるようにしてくれます。
専門用語を使うと、zip()
関数は複数の「イテラブルオブジェクト」を受け取り、それぞれの要素をまとめたタプルを生成する「イテレータ」を返します。
なんだか難しく聞こえますか?大丈夫です!
- イテラブルオブジェクト:
for
ループで要素を一つずつ取り出せるもの。リストやタプル、文字列などがこれにあたります。 - イテレータ:順番にデータを取り出すための「装置」のようなものです。
next()
という命令で次のデータを呼び出せます。
for
ループと組み合わせることで、このイテレータから自動的に要素を一つずつ取り出せるので、難しいことは考えなくても大丈夫ですよ!
zip関数の基本的な使い方
百聞は一見にしかず。さっそく先ほどの例をzip()
を使って書き換えてみましょう。
names = ['佐藤', '鈴木', '高橋']
scores = [90, 85, 95]
# zip関数で2つのリストをまとめる!
for name, score in zip(names, scores):
print(f'{name}さんの点数は{score}点です。')
実行結果:
佐藤さんの点数は90点です。 鈴木さんの点数は85点です。 高橋さんの点数は95点です。 |
どうでしょうか?
インデックスを使ったrange(len(...))のコードと比べて、はるかにスッキリして、やりたいことが直接的に表現されていると思いませんか?
for name, score in zip(names, scores):
の部分で、
zip(names, scores)
が、names
とscores
から要素を一つずつ取り出し、('佐藤', 90)
というペア(タプル)を作ります。for name, score in ...
の部分で、そのペアをname
とscore
という2つの変数にそれぞれ代入してくれているのです。(これをアンパックと呼びます)- 2周目のループでは
('鈴木', 85)
が、3周目では('高橋', 95)
が取り出され、リストの最後まで処理が続きます。
もしリストの長さが違ったらどうなる?
ここで一つ、大切な注意点があります。
「もし、zipに渡すリストの要素数が違っていたら、どうなっちゃうの?」という疑問です。
例えば、一人の点数が未入力で、scores
リストの要素が一つ少ない場合を考えてみましょう。
names = ['佐藤', '鈴木', '高橋']
scores = [90, 85] # 高橋さんの点数がない!
for name, score in zip(names, scores):
print(f'{name}さんの点数は{score}点です。')
佐藤さんの点数は90点です。 鈴木さんの点数は85点です。 |
見ての通り、エラーにはならず、高橋さん
のデータは無視されました。
zip()
関数は、渡されたリストのうち、最も要素数が少ないリストが終わった時点で処理を終了します。
これもジッパーの例えで考えると分かりやすいですね。左右の長さが違うジッパーを閉めようとしても、短い方が終わった時点でそれ以上は閉められません。zip()
もそれと同じ動きをする、と覚えておいてください!
便利な応用テクニック
zip()
は、単にループを回すだけでなく、他の機能と組み合わせることでさらに輝きます。
2つのリストから辞書を作る
これはzip()の最も代表的で便利な使い方の一つです!
キーのリストと値のリストから、一発で辞書(dict)オブジェクトを作成できます。
keys = ['name', 'age', 'city']
values = ['山田', 30, '東京']
# zipとdictを組み合わせる!
profile_dict = dict(zip(keys, values))
print(profile_dict)
# 出力: {'name': '山田', 'age': 30, 'city': '東京'}
forループを一行も書くことなく、あっという間に辞書が完成しました。これは非常に強力なので、ぜひ覚えておきましょう!
ジッパーを逆方向に開く!?「アンジップ」
zip()でまとめたものを、元のリストのように分離したい(アンジップしたい)場面もあるかもしれません。
そんな時は、zip()とアスタリスク(*)を組み合わせて使います。
pairs = [('佐藤', 90), ('鈴木', 85), ('高橋', 95)]
# アスタリスク(*)を付けてzipに渡す!
names, scores = zip(*pairs)
print(f'名前リスト: {names}')
print(f'点数リスト: {scores}')
名前リスト: ('佐藤', '鈴木', '高橋') 点数リスト: (90, 85, 95) |
見事に、ペアのリストが、名前だけのタプルと点数だけのタプルに分離されましたね。
まとめと今後の学習
今回は、複数のリストをエレガントに扱うためのzip()
関数について解説しました。
zip()
は複数のリストをまとめ、同じ順番の要素のペアを作る。for
ループと組み合わせると、コードが非常にスッキリする。- 処理は、一番短いリストの長さに合わせて終了する。
dict()
と組み合わせれば、簡単に辞書が作れる。
インデックスを使ったfor i in range(len(...))
というコードを見かけたら、「これはzip()
を使えばもっと綺麗に書けるな!」と考えてみる癖をつけてみてください。あなたのPythonコードが、一段と洗練されること間違いなしです!
もし、リストの長さが違う場合でも、短い方に合わせるのではなく、長い方に合わせて処理を続けたい場合はどうすれば良いでしょうか?そんな時は、itertools
というライブラリにあるzip_longest()
という関数を調べてみるのが次のステップとしておすすめです。
ぜひzip()
を使いこなして、快適なPythonプログラミングを楽しんでくださいね!