「2つのリストを同じタイミングで処理したい」
「名前のリストと年齢のリストをペアにして扱いたい」
このような場面で非常に便利なのが、Pythonのzip()
関数です。
zip()
を使うと、複数のリストやタプルを並列に処理することができ、コードがとても読みやすくなります。
この記事では、zip()
の基本的な使い方から、ループ処理、データ変換への応用、注意点まで、初心者の方にもわかりやすく解説します。
zip関数の基本的な仕組み

zipの基本構文
zip()
関数は、複数のイテラブル(リスト、タプルなど)を受け取り、対応する位置の要素同士をタプルにまとめます。
# 基本的な使い方
fruits = ["りんご", "バナナ", "オレンジ"]
colors = ["赤", "黄色", "オレンジ色"]
# zipで組み合わせる
combined = zip(fruits, colors)
print(list(combined))
実行結果:
[('りんご', '赤'), ('バナナ', '黄色'), ('オレンジ', 'オレンジ色')]
zipの動作を詳しく見る
names = ["田中", "佐藤", "鈴木"]
ages = [25, 30, 28]
jobs = ["エンジニア", "デザイナー", "営業"]
# zipオブジェクトを作成
zipped_data = zip(names, ages, jobs)
print(f"zipオブジェクト: {zipped_data}")
# リストに変換して内容を確認
result = list(zipped_data)
print(f"リスト化した結果: {result}")
# 各タプルの内容
for i, item in enumerate(result):
print(f"{i}番目: {item}")
実行結果:
zipオブジェクト: <zip object at 0x...>
リスト化した結果: [('田中', 25, 'エンジニア'), ('佐藤', 30, 'デザイナー'), ('鈴木', 28, '営業')]
0番目: ('田中', 25, 'エンジニア')
1番目: ('佐藤', 30, 'デザイナー')
2番目: ('鈴木', 28, '営業')
従来の方法と比較
# 従来の方法(インデックスを使用)
names = ["田中", "佐藤", "鈴木"]
ages = [25, 30, 28]
print("従来の方法:")
for i in range(len(names)):
print(f"{names[i]}さんは{ages[i]}歳です")
print("\nzip()を使った方法:")
for name, age in zip(names, ages):
print(f"{name}さんは{age}歳です")
実行結果:
従来の方法:
田中さんは25歳です
佐藤さんは30歳です
鈴木さんは28歳です
zip()を使った方法:
田中さんは25歳です
佐藤さんは30歳です
鈴木さんは28歳です
for文との組み合わせで同時ループ
2つのリストの同時処理
subjects = ["数学", "英語", "理科"]
scores = [85, 92, 78]
print("テスト結果:")
for subject, score in zip(subjects, scores):
if score >= 90:
evaluation = "優秀"
elif score >= 80:
evaluation = "良好"
else:
evaluation = "要努力"
print(f" {subject}: {score}点 ({evaluation})")
実行結果:
テスト結果:
数学: 85点 (良好)
英語: 92点 (優秀)
理科: 78点 (要努力)
3つ以上のリストの同時処理
cities = ["東京", "大阪", "名古屋"]
populations = [1400, 880, 230] # 万人
prefectures = ["東京都", "大阪府", "愛知県"]
print("主要都市の情報:")
for city, pop, pref in zip(cities, populations, prefectures):
print(f" {city}({pref}): 人口約{pop}万人")
実行結果:
主要都市の情報:
東京(東京都): 人口約1400万人
大阪(大阪府): 人口約880万人
名古屋(愛知県): 人口約230万人
インデックス付きの処理
products = ["パソコン", "マウス", "キーボード"]
prices = [80000, 2000, 5000]
print("商品一覧:")
for i, (product, price) in enumerate(zip(products, prices), 1):
print(f" {i}. {product}: {price:,}円")
実行結果:
商品一覧:
1. パソコン: 80,000円
2. マウス: 2,000円
3. キーボード: 5,000円
要素数が異なる場合の動作

短い方に合わせて切り捨て
zip()
は、最も短いリストの長さに合わせて動作します。
long_list = [1, 2, 3, 4, 5]
short_list = ['a', 'b', 'c']
result = list(zip(long_list, short_list))
print(f"元のリスト1: {long_list}")
print(f"元のリスト2: {short_list}")
print(f"zip結果: {result}")
print(f"4と5は切り捨てられました")
実行結果:
元のリスト1: [1, 2, 3, 4, 5]
元のリスト2: ['a', 'b', 'c']
zip結果: [(1, 'a'), (2, 'b'), (3, 'c')]
4と5は切り捨てられました
長さの違いを事前にチェック
def safe_zip(*lists):
"""長さをチェックしてからzipする関数"""
lengths = [len(lst) for lst in lists]
if len(set(lengths)) > 1:
print(f"警告: リストの長さが異なります {lengths}")
print(f"最短の長さ {min(lengths)} に合わせて処理します")
return zip(*lists)
# 使用例
list1 = ["A", "B", "C", "D"]
list2 = [1, 2, 3]
result = list(safe_zip(list1, list2))
print(f"結果: {result}")
実行結果:
警告: リストの長さが異なります [4, 3]
最短の長さ 3 に合わせて処理します
結果: [('A', 1), ('B', 2), ('C', 3)]
itertools.zip_longestで全要素を保持
from itertools import zip_longest
list1 = [1, 2, 3, 4, 5]
list2 = ['a', 'b', 'c']
# 通常のzip
normal_zip = list(zip(list1, list2))
print(f"通常のzip: {normal_zip}")
# zip_longest(不足分はNoneで埋める)
long_zip = list(zip_longest(list1, list2))
print(f"zip_longest: {long_zip}")
# 不足分を指定の値で埋める
filled_zip = list(zip_longest(list1, list2, fillvalue='?'))
print(f"fillvalue指定: {filled_zip}")
実行結果:
通常のzip: [(1, 'a'), (2, 'b'), (3, 'c')]
zip_longest: [(1, 'a'), (2, 'b'), (3, 'c'), (4, None), (5, None)]
fillvalue指定: [(1, 'a'), (2, 'b'), (3, 'c'), (4, '?'), (5, '?')]
アンパック(zip(*iterables))の活用
基本的なアンパック
アスタリスク*
を使うと、タプルのリストを「列ごと」に分解できます。
# ペアのリストを列ごとに分解
pairs = [("田中", 25), ("佐藤", 30), ("鈴木", 28)]
names, ages = zip(*pairs)
print(f"名前: {names}")
print(f"年齢: {ages}")
print(f"名前のタイプ: {type(names)}")
実行結果:
名前: ('田中', '佐藤', '鈴木')
年齢: (25, 30, 28)
名前のタイプ: <class 'tuple'>
zipとアンパックの相互変換
# 元のデータ
fruits = ["りんご", "バナナ", "オレンジ"]
colors = ["赤", "黄色", "オレンジ色"]
print("1. 元のデータ:")
print(f" fruits: {fruits}")
print(f" colors: {colors}")
# zipで結合
pairs = list(zip(fruits, colors))
print(f"\n2. zipで結合: {pairs}")
# アンパックで分解
fruits_back, colors_back = zip(*pairs)
print(f"\n3. アンパックで分解:")
print(f" fruits: {list(fruits_back)}")
print(f" colors: {list(colors_back)}")
実行結果:
1. 元のデータ:
fruits: ['りんご', 'バナナ', 'オレンジ']
colors: ['赤', '黄色', 'オレンジ色']
2. zipで結合: [('りんご', '赤'), ('バナナ', '黄色'), ('オレンジ', 'オレンジ色')]
3. アンパックで分解:
fruits: ['りんご', 'バナナ', 'オレンジ']
colors: ['赤', '黄色', 'オレンジ色']
行列の転置
# 2次元リスト(行列)の転置
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print("元の行列:")
for row in matrix:
print(f" {row}")
# 転置(行と列を入れ替え)
transposed = list(zip(*matrix))
print(f"\n転置後: {transposed}")
print("\n転置後の行列:")
for row in transposed:
print(f" {list(row)}")
実行結果:
元の行列:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
転置後: [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
転置後の行列:
[1, 4, 7]
[2, 5, 8]
[3, 6, 9]
実用的な応用例

辞書の作成
# キーと値のリストから辞書を作成
keys = ["name", "age", "job", "city"]
values = ["田中", 25, "エンジニア", "東京"]
# zipとdict()で辞書作成
person = dict(zip(keys, values))
print(f"作成した辞書: {person}")
# 複数人分のデータを辞書のリストに
names = ["田中", "佐藤", "鈴木"]
ages = [25, 30, 28]
jobs = ["エンジニア", "デザイナー", "営業"]
people = []
for name, age, job in zip(names, ages, jobs):
person_dict = {
"name": name,
"age": age,
"job": job
}
people.append(person_dict)
print(f"\n人物リスト:")
for person in people:
print(f" {person}")
実行結果:
作成した辞書: {'name': '田中', 'age': 25, 'job': 'エンジニア', 'city': '東京'}
人物リスト:
{'name': '田中', 'age': 25, 'job': 'エンジニア'}
{'name': '佐藤', 'age': 30, 'job': 'デザイナー'}
{'name': '鈴木', 'age': 28, 'job': '営業'}
CSVデータの処理
# CSVのような形式のデータ処理
headers = ["商品名", "価格", "在庫"]
data_rows = [
["パソコン", 80000, 5],
["マウス", 2000, 20],
["キーボード", 5000, 15]
]
print("商品情報:")
for row in data_rows:
# ヘッダーとデータをペアにして表示
for header, value in zip(headers, row):
print(f" {header}: {value}")
print() # 空行
# 辞書形式での処理
products = []
for row in data_rows:
product = dict(zip(headers, row))
products.append(product)
print("辞書形式:")
for product in products:
print(f" {product}")
実行結果:
商品情報:
商品名: パソコン
価格: 80000
在庫: 5
商品名: マウス
価格: 2000
在庫: 20
商品名: キーボード
価格: 5000
在庫: 15
辞書形式:
{'商品名': 'パソコン', '価格': 80000, '在庫': 5}
{'商品名': 'マウス', '価格': 2000, '在庫': 20}
{'商品名': 'キーボード', '価格': 5000, '在庫': 15}
成績処理システム
# 学生の成績処理
students = ["田中", "佐藤", "鈴木", "高橋"]
math_scores = [85, 92, 78, 96]
english_scores = [88, 85, 95, 89]
science_scores = [82, 89, 91, 93]
print("成績一覧:")
print(f"{'名前':<8} {'数学':<4} {'英語':<4} {'理科':<4} {'平均':<6}")
print("-" * 30)
for name, math, eng, sci in zip(students, math_scores, english_scores, science_scores):
average = (math + eng + sci) / 3
print(f"{name:<8} {math:<4} {eng:<4} {sci:<4} {average:<6.1f}")
# 教科別の統計
print(f"\n教科別平均点:")
subjects = ["数学", "英語", "理科"]
score_lists = [math_scores, english_scores, science_scores]
for subject, scores in zip(subjects, score_lists):
avg = sum(scores) / len(scores)
print(f" {subject}: {avg:.1f}点")
実行結果:
成績一覧:
名前 数学 英語 理科 平均
------------------------------
田中 85 88 82 85.0
佐藤 92 85 89 88.7
鈴木 78 95 91 88.0
高橋 96 89 93 92.7
教科別平均点:
数学: 87.8点
英語: 89.2点
理科: 88.8点
座標データの処理
# 2次元座標の処理
x_coords = [0, 1, 3, 4, 6]
y_coords = [0, 2, 1, 5, 3]
print("座標リスト:")
for i, (x, y) in enumerate(zip(x_coords, y_coords)):
distance = (x**2 + y**2)**0.5 # 原点からの距離
print(f" 点{i+1}: ({x}, {y}) - 原点からの距離: {distance:.2f}")
# 座標を移動させる
move_x, move_y = 2, 3
print(f"\n全ての点を({move_x}, {move_y})だけ移動:")
for old_x, old_y in zip(x_coords, y_coords):
new_x, new_y = old_x + move_x, old_y + move_y
print(f" ({old_x}, {old_y}) → ({new_x}, {new_y})")
実行結果:
座標リスト:
点1: (0, 0) - 原点からの距離: 0.00
点2: (1, 2) - 原点からの距離: 2.24
点3: (3, 1) - 原点からの距離: 3.16
点4: (4, 5) - 原点からの距離: 6.40
点5: (6, 3) - 原点からの距離: 6.71
全ての点を(2, 3)だけ移動:
(0, 0) → (2, 3)
(1, 2) → (3, 5)
(3, 1) → (5, 4)
(4, 5) → (6, 8)
(6, 3) → (8, 6)
zipの注意点と落とし穴
zipオブジェクトは1回だけ使用可能
zip()
はイテレータオブジェクトを返すため、一度使用すると空になります。
numbers = [1, 2, 3]
letters = ['a', 'b', 'c']
# zipオブジェクトを作成
zipped = zip(numbers, letters)
print(f"zipオブジェクト: {zipped}")
# 1回目の使用
print("1回目の使用:")
for num, letter in zipped:
print(f" {num}: {letter}")
# 2回目の使用(空になる)
print("\n2回目の使用:")
for num, letter in zipped:
print(f" {num}: {letter}")
print(" 何も表示されませんでした")
# 解決策:リストに変換して保存
zipped_list = list(zip(numbers, letters))
print(f"\nリスト化: {zipped_list}")
print("これなら何度でも使用できます")
実行結果:
zipオブジェクト: <zip object at 0x...>
1回目の使用:
1: a
2: b
3: c
2回目の使用:
何も表示されませんでした
リスト化: [(1, 'a'), (2, 'b'), (3, 'c')]
これなら何度でも使用できます
メモリ効率との兼ね合い
# 大量のデータでのメモリ効率
def process_large_data():
# 仮想的な大量データ
data1 = range(1000000) # 100万個の数値
data2 = range(1000000, 2000000) # 100万個の数値
# zipオブジェクトは必要な時だけメモリを使用
print("zipオブジェクトを直接使用(メモリ効率良):")
count = 0
for a, b in zip(data1, data2):
if a + b > 1500000: # 条件に合う最初の要素だけ処理
print(f" 最初の条件合致: {a} + {b} = {a + b}")
break
count += 1
print(f" 処理した要素数: {count + 1}")
process_large_data()
空のリストでの動作
# 空のリストを含む場合
list1 = [1, 2, 3]
list2 = [] # 空のリスト
list3 = ['a', 'b', 'c']
result = list(zip(list1, list2, list3))
print(f"空のリストがある場合: {result}")
print("→ 結果も空になります")
# 空かどうかのチェック
lists = [list1, list2, list3]
for i, lst in enumerate(lists):
if not lst:
print(f"リスト{i+1}が空です")
実行結果:
空のリストがある場合: []
→ 結果も空になります
リスト2が空です
他の関数との組み合わせ
enumerate()との組み合わせ
fruits = ["りんご", "バナナ", "オレンジ"]
prices = [150, 100, 200]
print("商品番号付きリスト:")
for index, (fruit, price) in enumerate(zip(fruits, prices), 1):
print(f" {index}. {fruit}: {price}円")
実行結果:
商品番号付きリスト:
1. りんご: 150円
2. バナナ: 100円
3. オレンジ: 200円
map()との組み合わせ
numbers1 = [1, 2, 3, 4]
numbers2 = [10, 20, 30, 40]
# 2つのリストの要素を足し算
sums = list(map(lambda pair: pair[0] + pair[1], zip(numbers1, numbers2)))
print(f"足し算結果: {sums}")
# よりシンプルな書き方
sums2 = [a + b for a, b in zip(numbers1, numbers2)]
print(f"リスト内包表記: {sums2}")
実行結果:
足し算結果: [11, 22, 33, 44]
リスト内包表記: [11, 22, 33, 44]
まとめ
zip()
関数は、Pythonで複数のリストを同時に処理するための強力で便利な機能です。
重要なポイント
- 複数のイテラブルを並列に処理できる
- 最も短いリストの長さに合わせて動作
- zipオブジェクトは1回だけ使用可能
- アンパック(
zip(*iterables)
)で列ごとの分解が可能
よく使うパターン
用途 | 書き方 | 例 |
---|---|---|
同時ループ | for a, b in zip(list1, list2): | ペア処理 |
辞書作成 | dict(zip(keys, values)) | キーと値の結合 |
行列転置 | list(zip(*matrix)) | 行と列の入れ替え |
データ分解 | col1, col2 = zip(*pairs) | 列ごとの抽出 |
適用場面
- 複数のリストの同時処理
- CSVデータの列ごと処理
- 座標や成績データの管理
- 辞書の動的作成
- 行列やテーブルデータの変換
注意すべき点
- 長さの異なるリストでは短い方に合わせられる
- zipオブジェクトは再利用できない
- 大量データでは必要に応じてリスト化
コメント