Pythonのzip関数の使い方を解説!複数のリストをスマートにまとめる技
Pythonでプログラムを書いているとき、複数のリストを同時に扱いたい場面ってよくありますよね。
例えば、ユーザー名のリストと、それに対応する年齢のリストを組み合わせて処理したいときなどです。
そんなときに欠かせないのが、今回詳しく解説する zip関数 です。 この関数を使いこなせると、コードの行数が減るだけでなく、読みやすさも格段に向上します。
エンジニア歴10年の私自身、この関数を知るまではインデックス番号を使って無理やりループを回していました。 しかし、zip関数を覚えてからは、まるで魔法のようにコードがスッキリしたことを今でも覚えています。
今回は、初心者がまず押さえるべき基本から、現場で役立つ少し高度なテクニックまで、詳しく解説します。
zip関数とは何か?その直感的なイメージ¶
そもそもzip関数とは、複数のイテラブル(リストやタプルなど)を引数に取り、それらの要素を ペアにしてまとめる ための関数です。 名前の通り、洋服のジッパーを閉めるように、バラバラだったデータを一つに束ねるイメージを持つと分かりやすいでしょう。
複数のリストをバラバラに管理するのではなく、セットとして扱うことで、データの関連性が一目で分かるようになります。 まずは、このジッパーのイメージを頭の片隅に置いておいてくださいね。
なぜzip関数を使う必要があるのか¶
なぜわざわざ新しい関数を覚える必要があるのか、疑問に思う方もいるかもしれません。 多くの初心者は、複数のリストを同時に回すために、リストの長さを測ってインデックス(添字)を使おうとします。
しかし、その書き方だとコードが複雑になりやすく、タイピングミスによるバグも発生しやすくなります。 zip関数を使えば、インデックスを意識することなく、スマートに要素を取り出すことができるのです。
他の言語との違い¶
他のプログラミング言語では、似たような処理をするためにもっと複雑な記述が必要なことも珍しくありません。 Pythonのzip関数は、言語の哲学である簡潔さを象徴するような非常に強力なツールです。
これを知っているかどうかで、あなたの書くコードがPythonらしい(Pythonicである)かどうかが決まると言っても過言ではありません。 では、具体的な書き方を見ていきましょう。
zip関数の基本的な使い方¶
zip関数の使い方は、シンプルです。 まとめたいリストをカンマ区切りで括弧の中に入れるだけで、ペアになったデータが生成されます。
2つのリストを組み合わせる¶
まずは、もっとも一般的な2つのリストを組み合わせる例を見てみましょう。 ここでは名前のリストと、その人の好きな食べ物のリストを用意しました。
names = ["田中", "佐藤", "鈴木"]
foods = ["寿司", "焼肉", "ラーメン"]
combined = zip(names, foods)
print(list(combined))
# 出力: [('田中', '寿司'), ('佐藤', '焼肉'), ('鈴木', 'ラーメン')]
このように、それぞれのリストから同じ位置にある要素が取り出され、タプルの形にまとめられます。
注意点として、zip関数が返すのは zipオブジェクト という特殊な形式なので、中身を確認したいときは list() などで変換する必要があります。
3つ以上のリストでも大丈夫¶
zip関数のすごいところは、引数として渡すリストの数に制限がないことです。 3つでも4つでも、同じようにペア(正確にはn組のタプル)にしてくれます。
names = ["田中", "佐藤", "鈴木"]
ages = [25, 30, 22]
cities = ["東京", "大阪", "福岡"]
for name, age, city in zip(names, ages, cities):
print(f"{name}さんは{age}歳で、{city}在住です。")
複数の情報を一つのループで同時に扱えるため、データの関連付けが非常に楽になります。 バラバラのリストから値を引っ張ってくるよりも、ミスが起きにくい安心感がありますよね。
【関連記事】Pythonのリスト内包表記を使いこなせ!3行のループを1行にまとめる書き方
forループとの組み合わせが最強¶
zip関数がもっとも輝く瞬間は、forループ の中で使ったときです。
わざわざ list() に変換することなく、そのままループの対象として指定できます。
アンパックを使ったスマートな記述¶
ループの中で各要素を取り出すとき、タプルのまま扱うのではなく、別々の変数に展開して受け取ることができます。 これをアンパックと呼びますが、zip関数との相性は抜群です。
points = [80, 95, 70]
max_points = [100, 100, 100]
for score, total in zip(points, max_points):
percentage = (score / total) * 100
print(f"得点率は {percentage}% です。")
インデックス番号を使って points[i] のように書く必要がないため、コードが非常に読みやすくなりますよね。
誰が読んでも「2つのリストから値を取り出して計算しているんだな」と伝わります。
range(len()) を卒業しよう¶
初心者がやりがちな書き方に for i in range(len(list_a)): というものがあります。
この書き方は間違いではありませんが、Pythonの世界ではあまり推奨されません。
インデックス管理をPythonに任せて、私たちはデータそのものに集中する。 これが、zip関数を使う最大のメリットであり、プロが実践しているスタイルです。
リストの長さが違う場合はどうなる?¶
ここで一つ、気になる疑問が出てきませんか? もし組み合わせようとしているリストの長さが違っていたら、zip関数はどう反応するのでしょうか。
実務では、データが欠けていたり、取得元の数が合わなかったりすることはよくあります。 この挙動を理解していないと、意図せずデータが消えてしまう原因になります。
短い方に合わせられる基本挙動¶
標準のzip関数は、もっとも短いリスト の要素がなくなった時点で、処理を終了します。 長い方のリストに残っている要素は、残念ながら無視されてしまうのです。
list_a = [1, 2, 3, 4, 5]
list_b = ["A", "B", "C"]
for num, char in zip(list_a, list_b):
print(num, char)
# 3までしか出力されず、4と5は無視されます
エラーは出ませんが、データが勝手に切り捨てられるのは怖いですよね。 データ不整合に気づかずに処理が進んでしまうのを防げる、最新の設定を見てみましょう。
Python 3.10以降の新機能 strict引数¶
Python 3.10というバージョンから、この問題に対する素晴らしい解決策が導入されました。
それが strict=True というオプション引数です。
# リストの長さが違うとエラーを投げてくれる
for num, char in zip(list_a, list_b, strict=True):
print(num, char)
# ValueError: zip() argument 2 is shorter than argument 1
これを設定しておけば、長さが違うときにプログラムが即座にエラーを出してくれます。 意図しないデータの欠落を未然に防げるため、現代の開発では必須のテクニックです。
長い方に合わせたいときは itertools.zip_longest¶
どうしても長い方のリストに合わせて、欠けている部分を埋めたい場合もありますよね。
そのときは、標準のzip関数ではなく itertools モジュールにある zip_longest を使いましょう。
欠損値を埋める fillvalue¶
zip_longest を使うと、足りない部分を特定の文字や数値で埋めることができます。
デフォルトでは None が入りますが、自由に変更可能です。
from itertools import zip_longest
list_a = [1, 2, 3]
list_b = ["A"]
for num, char in zip_longest(list_a, list_b, fillvalue="欠損"):
print(num, char)
# 出力: 1 A, 2 欠損, 3 欠損
データの整形や、CSVファイルなどの表形式データを作るときに非常に重宝します。
場面に応じて、標準のzipと zip_longest を使い分けられるようになると、脱・初心者です。
zip関数を使った「逆引き」:アンジップ(解体)¶
zip関数でまとめたデータを、元のバラバラの状態に戻したいときはどうすればいいでしょうか。 実は、zip関数には アンジップ と呼ばれる、面白い逆転のテクニックがあります。
アスタリスク(*)の魔法¶
引数のリストにアスタリスク * をつけてzip関数に渡すと、まとめられたペアを解体してくれます。
言葉にすると複雑ですが、コードを見るとそのシンプルさに驚くはずです。
pairs = [("田中", 25), ("佐藤", 30), ("鈴木", 22)]
# アンジップして名前と年齢のリストに戻す
names, ages = zip(*pairs)
print(names) # ('田中', '佐藤', '鈴木')
print(ages) # (25, 30, 22)
行列の転置(縦と横を入れ替える)のような処理をしたいときに、このテクニックが非常に役立ちます。 10年エンジニアをやっていても、この書き方は「Pythonっぽくて賢いな」と感心してしまいます。
辞書(dict)を爆速で作るテクニック¶
zip関数の応用として、もっとも便利なのが 辞書の作成 です。 キーとなるリストと、値となるリストがあれば、一行で辞書を構築できます。
dict関数との組み合わせ¶
通常、ループを回して一つずつ辞書に格納していくコードを書きますが、zipを使えばその必要はありません。
dict() 関数の引数に zip() を渡すだけです。
keys = ["id", "name", "role"]
values = [101, "Python太郎", "開発者"]
user_dict = dict(zip(keys, values))
print(user_dict)
# {'id': 101, 'name': 'Python太郎', 'role': '開発者'}
設定ファイルから読み込んだデータを構造化したり、データベースの結果を整形したりする際に大活躍します。 コードが劇的に短くなるので、ぜひ今日から使ってみてください。
【関連記事】綺麗なコードって何?初心者から一歩抜け出す「リーダブルコード」の3つの基本
zip関数のパフォーマンスとイテレータの性質¶
ここからは少し中級者向けの話になりますが、zip関数の 正体 について触れておきます。 zip関数が返すのはリストではなく、イテレータ(zipオブジェクト)です。
メモリを節約する「遅延評価」¶
イテレータとは、その要素が必要になったときに初めて値を生成する仕組みのことです。 例えば100万個の要素を持つ巨大なリスト同士をzipしても、その瞬間に新しい巨大なリストが作られるわけではありません。
# 巨大なデータを扱っても、この時点ではメモリをほとんど消費しない
zipped_data = zip(huge_list_a, huge_list_b)
実際にループの中で取り出すときに、初めてペアが作られます。 これにより、メモリを節約しながら効率よく大量のデータを処理することができるのです。
一度使うと消えてしまう?¶
イテレータの注意点として、一度中身を最後まで読み取ると、空っぽになってしまうという性質があります。
もう一度同じ zipped_data をループで回そうとしても、何も出力されません。
zipped = zip([1, 2], ["A", "B"])
list(zipped) # ここで中身を使い切る
list(zipped) # 2回目は [] になる
もし何度も使い回したい場合は、list() でリストに変換して保存しておく必要があります。
この性質を知らないと、「なぜか2回目からデータが消える」という謎のバグに悩まされることになります。
現場で役立つ活用パターン一覧¶
zip関数の使い方を整理するために、よく使うパターンを一覧表にまとめました。 困ったときの逆引きとして活用してください。
| 実現したいこと | 使う方法・テクニック | 特徴 |
|---|---|---|
| 複数のリストを同時に回す | for x, y in zip(a, b): |
最も基本的。コードがスッキリする。 |
| 辞書を一瞬で作る | dict(zip(keys, values)) |
データの構造化に最適。 |
| データのペアを作る | list(zip(a, b)) |
リスト形式で結果を保存できる。 |
| 長さの違いを検知する | zip(a, b, strict=True) |
Python 3.10以降。不整合を防ぐ。 |
| 欠損を埋めて結合する | itertools.zip_longest |
データ欠落を許容する場合に使う。 |
| ペアを解体(転置)する | zip(*zipped_data) |
行列の入れ替えなどに便利。 |
こうして見ると、zip関数がいかに多機能で、あらゆる場面を想定して設計されているかがわかりますね。 自分のやりたいことに合わせて、最適なモードを選べるようになりましょう。
エンジニア歴10年の私が伝えたいこと¶
プログラミングを始めたばかりの頃は、どうしても「目に見えるインデックス」に頼りたくなります。 私もそうでした。数字が動いている方が、なんとなくプログラムが動いている実感が湧くからです。
しかし、実務でのコードは「動く」だけでなく「メンテナンスしやすい」ことが求められます。
「i番目の要素を取り出して、j番目と組み合わせて…」と考えるのではなく、 「AグループとBグループをペアにする」と考える。
この思考のシフトが、エンジニアとしての抽象化能力を高めてくれます。
迷ったらPythonicを追求しよう¶
Pythonには「Python禅(The Zen of Python)」という哲学があります。 その中には「Simple is better than complex(単純さは複雑さに勝る)」という言葉があります。
zip関数はこの哲学を体現している関数の一つです。 「もっと短く、もっと分かりやすく書けないか?」と自問自答したとき、zip関数は常にあなたの力になってくれるはずです。
まとめ:zip関数を使いこなして効率アップ!¶
今回はPythonのzip関数について、基本から応用までたっぷりと解説してきました。 少し長くなってしまいましたが、重要なポイントを最後におさらいしましょう。
- zip関数 は、複数のリストをペアにして束ねる魔法の道具。
- forループ との組み合わせで、インデックス不要の美しいコードが書ける。
- strict引数 や zip_longest で、リストの長さの違いにも対応可能。
- アスタリスク を使えば、まとめたデータを解体することもできる。
- メモリ効率 が良く、巨大なデータでも高速に動作する。
最初は少し戸惑うかもしれませんが、一度馴染んでしまうと、もうこれなしでの開発は考えられなくなるでしょう。 ぜひ、今書いているあなたのコードにも、zip関数を取り入れてみてください。
きっと、昨日よりも少しだけ「美しく賢い」コードに生まれ変わるはずです。 これからもPythonの学習を楽しんで、一歩ずつスキルアップしていきましょう!
ここまでお読みいただきありがとうございました。