Pythonで繰り返し処理(ループ)を効率よく書きたいと思ったことはありませんか?
そんなときに活躍するのが、itertools(イター・ツールズ)モジュールです。
itertoolsは、標準ライブラリに含まれていて、メモリ効率が良く、高速な反復処理を実現できます。for文だけでは難しかった「組み合わせ」「繰り返し」「フィルタ処理」などが、1行で書けるようになります。
この記事では、定番の使い方から応用例、実際のプロジェクトで使える実践的なテクニックまで、itertoolsを徹底的にわかりやすく解説します。
この記事で学べること:
- itertoolsの基本概念とイテレータの仕組み
- 主要関数の使い方と実用例
itertoolsとは?基本概念を理解する

itertoolsモジュールの特徴
itertoolsは、Python標準ライブラリの中でも特に強力なモジュールの一つです。
「効率的なループのためのイテレータを作成する関数」を提供します。
主な特徴:
- メモリ効率:大量のデータを一度にメモリに読み込まない
- 遅延評価:必要な時にのみ値を生成
- 高速処理:C言語レベルで最適化された実装
- 組み合わせ:複雑なループ処理を簡潔に記述
- 標準搭載:追加インストール不要
インポート方法と基本的な使い方
import itertools
# または個別の関数をインポート
from itertools import count, cycle, repeat, product, combinations
Pythonに標準で含まれているため、追加インストールは不要です。
イテレータの基本概念
itertoolsの関数はイテレータ(iterator)を返します。
イテレータとは「一度に一つずつ値を返すオブジェクト」で、for文などと相性抜群です。
基本例:
import itertools
# 無限カウンター(1から始まる)
counter = itertools.count(1)
# 最初の5個だけ取得
for i, x in enumerate(counter):
if i >= 5:
break
print(x) # 1, 2, 3, 4, 5
出力結果:
1
2
3
4
5
重要なポイント:
- イテレータは一度しか使えない(使い切りオブジェクト)
- **list()**で明示的にリストに変換可能
- 大量データでもメモリを節約できる
無限イテレータ関数群

count():無限カウンター
指定した値から無限にカウントアップするイテレータを生成します。
基本構文:
itertools.count(start=0, step=1)
実用例:
from itertools import count
# 基本的な使用例
print("1から5まで:")
for i in count(1):
if i > 5:
break
print(i)
print("\n偶数を10個生成:")
even_numbers = count(0, 2) # 0から2ずつ増加
for i, num in enumerate(even_numbers):
if i >= 10:
break
print(num, end=' ')
print("\n\nIDジェネレーター:")
id_generator = count(1000)
print(f"ユーザーID: {next(id_generator)}") # 1000
print(f"ユーザーID: {next(id_generator)}") # 1001
print(f"ユーザーID: {next(id_generator)}") # 1002
出力結果:
1から5まで:
1
2
3
4
5
偶数を10個生成:
0 2 4 6 8 10 12 14 16 18
IDジェネレーター:
ユーザーID: 1000
ユーザーID: 1001
ユーザーID: 1002
cycle():要素の無限繰り返し
イテラブルの要素を無限に繰り返すイテレータを生成します。
基本構文:
itertools.cycle(iterable)
実用例:
from itertools import cycle
# 基本的な使用例
colors = cycle(['red', 'green', 'blue'])
print("色の無限ループ(最初の10個):")
for i, color in enumerate(colors):
if i >= 10:
break
print(f"{i+1}: {color}")
# 実践例:ラウンドロビン方式での処理
servers = cycle(['server1', 'server2', 'server3'])
requests = ['req1', 'req2', 'req3', 'req4', 'req5', 'req6']
print("\nサーバーへの負荷分散:")
for request in requests:
server = next(servers)
print(f"{request} → {server}")
出力結果:
色の無限ループ(最初の10個):
1: red
2: green
3: blue
4: red
5: green
6: blue
7: red
8: green
9: blue
10: red
サーバーへの負荷分散:
req1 → server1
req2 → server2
req3 → server3
req4 → server1
req5 → server2
req6 → server3
repeat():同じ値の繰り返し
指定した値を指定回数(または無限に)繰り返すイテレータを生成します。
基本構文:
itertools.repeat(object, times=None)
実用例:
from itertools import repeat
# 基本的な使用例
print("0を5回繰り返し:")
zeros = repeat(0, 5)
print(list(zeros))
# 無限繰り返し(危険なので注意!)
print("\n'Hello'を3回繰り返し:")
hellos = repeat('Hello', 3)
for greeting in hellos:
print(greeting)
# 実践例:初期値リストの作成
print("\nマトリックスの初期化:")
matrix_size = 3
initial_value = 0
matrix = [list(repeat(initial_value, matrix_size)) for _ in range(matrix_size)]
for row in matrix:
print(row)
# map()との組み合わせ例
print("\n各要素を2倍にする:")
numbers = [1, 2, 3, 4, 5]
multiplier = repeat(2)
doubled = list(map(lambda x, y: x * y, numbers, multiplier))
print(f"元の数値: {numbers}")
print(f"2倍した結果: {doubled}")
出力結果:
0を5回繰り返し:
[0, 0, 0, 0, 0]
'Hello'を3回繰り返し:
Hello
Hello
Hello
マトリックスの初期化:
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
各要素を2倍にする:
元の数値: [1, 2, 3, 4, 5]
2倍した結果: [2, 4, 6, 8, 10]
組み合わせ・順列関数群

product():直積(デカルト積)
複数のイテラブルの直積を生成します。全ての組み合わせを作成する際に便利です。
基本構文:
itertools.product(*iterables, repeat=1)
実用例:
from itertools import product
# 基本的な使用例
colors = ['red', 'green', 'blue']
sizes = ['S', 'M', 'L']
print("商品の全組み合わせ:")
for item in product(colors, sizes):
print(f"色: {item[0]}, サイズ: {item[1]}")
# repeatオプションの使用
print("\n3文字の組み合わせ(最初の10個のみ):")
letters = ['a', 'b', 'c']
for i, combo in enumerate(product(letters, repeat=3)):
if i >= 10:
break
print(''.join(combo))
# 実践例:座標の生成
print("\n3x3グリッドの座標:")
for x, y in product(range(3), range(3)):
print(f"({x}, {y})", end=' ')
print()
# パスワード生成例(簡単な例)
import string
print("\n4文字の英数字パスワード(最初の20個):")
chars = string.ascii_lowercase[:3] + string.digits[:3] # 'abc123'
for i, pwd in enumerate(product(chars, repeat=4)):
if i >= 20:
break
print(''.join(pwd), end=' ')
print()
出力結果:
商品の全組み合わせ:
色: red, サイズ: S
色: red, サイズ: M
色: red, サイズ: L
色: green, サイズ: S
色: green, サイズ: M
色: green, サイズ: L
色: blue, サイズ: S
色: blue, サイズ: M
色: blue, サイズ: L
3文字の組み合わせ(最初の10個のみ):
aaa
aab
aac
aba
abb
abc
aca
acb
acc
baa
3x3グリッドの座標:
(0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)
4文字の英数字パスワード(最初の20個):
aaaa aaab aaac aaa1 aaa2 aaa3 aaba aabb aabc aab1 aab2 aab3 aaca aacb aacc aac1 aac2 aac3 aa1a aa1b
permutations():順列
要素の順列(並び順が重要)を生成します。
基本構文:
itertools.permutations(iterable, r=None)
実用例:
from itertools import permutations
# 基本的な使用例
members = ['Alice', 'Bob', 'Charlie']
print("3人の並び順(順列):")
for i, perm in enumerate(permutations(members)):
print(f"{i+1}: {perm}")
# 長さを指定した順列
print("\n2人ずつの並び順:")
for perm in permutations(members, 2):
print(perm)
# 実践例:レースの順位
print("\nレースの順位(上位3名):")
runners = ['田中', '佐藤', '鈴木', '高橋']
for i, ranking in enumerate(permutations(runners, 3)):
if i >= 6: # 最初の6パターンのみ表示
break
print(f"1位: {ranking[0]}, 2位: {ranking[1]}, 3位: {ranking[2]}")
# 文字列の順列
print("\n'ABC'の全ての並び替え:")
for perm in permutations('ABC'):
print(''.join(perm))
出力結果:
3人の並び順(順列):
1: ('Alice', 'Bob', 'Charlie')
2: ('Alice', 'Charlie', 'Bob')
3: ('Bob', 'Alice', 'Charlie')
4: ('Bob', 'Charlie', 'Alice')
5: ('Charlie', 'Alice', 'Bob')
6: ('Charlie', 'Bob', 'Alice')
2人ずつの並び順:
('Alice', 'Bob')
('Alice', 'Charlie')
('Bob', 'Alice')
('Bob', 'Charlie')
('Charlie', 'Alice')
('Charlie', 'Bob')
レースの順位(上位3名):
1位: 田中, 2位: 佐藤, 3位: 鈴木
1位: 田中, 2位: 佐藤, 3位: 高橋
1位: 田中, 2位: 鈴木, 3位: 佐藤
1位: 田中, 2位: 鈴木, 3位: 高橋
1位: 田中, 2位: 高橋, 3位: 佐藤
1位: 田中, 2位: 高橋, 3位: 鈴木
'ABC'の全ての並び替え:
ABC
ACB
BAC
BCA
CAB
CBA
combinations():組み合わせ
要素の組み合わせ(順序は関係なし)を生成します。
基本構文:
itertools.combinations(iterable, r)
実用例:
from itertools import combinations
# 基本的な使用例
members = ['Alice', 'Bob', 'Charlie', 'David']
print("2人組のペア:")
for pair in combinations(members, 2):
print(pair)
# 実践例:チーム分け
print("\n3人組のチーム:")
for team in combinations(members, 3):
print(team)
# 数値の組み合わせ
numbers = [1, 2, 3, 4, 5]
print("\n数値から3つを選ぶ組み合わせ:")
for combo in combinations(numbers, 3):
print(combo)
# 宝くじシミュレーション
print("\n宝くじの番号(1-10から3つ選択):")
lottery_numbers = range(1, 11)
for i, combo in enumerate(combinations(lottery_numbers, 3)):
if i >= 10: # 最初の10通りのみ
break
print(f"番号: {combo}")
出力結果:
2人組のペア:
('Alice', 'Bob')
('Alice', 'Charlie')
('Alice', 'David')
('Bob', 'Charlie')
('Bob', 'David')
('Charlie', 'David')
3人組のチーム:
('Alice', 'Bob', 'Charlie')
('Alice', 'Bob', 'David')
('Alice', 'Charlie', 'David')
('Bob', 'Charlie', 'David')
数値から3つを選ぶ組み合わせ:
(1, 2, 3)
(1, 2, 4)
(1, 2, 5)
(1, 3, 4)
(1, 3, 5)
(1, 4, 5)
(2, 3, 4)
(2, 3, 5)
(2, 4, 5)
(3, 4, 5)
宝くじの番号(1-10から3つ選択):
番号: (1, 2, 3)
番号: (1, 2, 4)
番号: (1, 2, 5)
番号: (1, 2, 6)
番号: (1, 2, 7)
番号: (1, 2, 8)
番号: (1, 2, 9)
番号: (1, 2, 10)
番号: (1, 3, 4)
番号: (1, 3, 5)
combinations_with_replacement():重複組み合わせ
同じ要素を複数回選択できる組み合わせを生成します。
実用例:
from itertools import combinations_with_replacement
# 基本的な使用例
colors = ['red', 'green', 'blue']
print("重複ありの2色組み合わせ:")
for combo in combinations_with_replacement(colors, 2):
print(combo)
# 実践例:コインの組み合わせ
coins = [1, 5, 10] # 1円、5円、10円
print("\n硬貨3枚の組み合わせ(重複あり):")
for combo in combinations_with_replacement(coins, 3):
total = sum(combo)
print(f"硬貨: {combo}, 合計: {total}円")
出力結果:
重複ありの2色組み合わせ:
('red', 'red')
('red', 'green')
('red', 'blue')
('green', 'green')
('green', 'blue')
('blue', 'blue')
硬貨3枚の組み合わせ(重複あり):
硬貨: (1, 1, 1), 合計: 3円
硬貨: (1, 1, 5), 合計: 7円
硬貨: (1, 1, 10), 合計: 12円
硬貨: (1, 5, 5), 合計: 11円
硬貨: (1, 5, 10), 合計: 16円
硬貨: (1, 10, 10), 合計: 21円
硬貨: (5, 5, 5), 合計: 15円
硬貨: (5, 5, 10), 合計: 20円
硬貨: (5, 10, 10), 合計: 25円
硬貨: (10, 10, 10), 合計: 30円
集約・変換関数群

accumulate():累積計算
累積和や累積積などの累積計算を行います。
基本構文:
itertools.accumulate(iterable, func=operator.add, initial=None)
実用例:
from itertools import accumulate
import operator
# 基本的な累積和
numbers = [1, 2, 3, 4, 5]
print("累積和:")
cumsum = list(accumulate(numbers))
print(f"元の数値: {numbers}")
print(f"累積和: {cumsum}")
# 累積積
print("\n累積積:")
cumulative_product = list(accumulate(numbers, operator.mul))
print(f"累積積: {cumulative_product}")
# 累積最大値
print("\n累積最大値:")
data = [3, 1, 4, 1, 5, 9, 2, 6]
cumulative_max = list(accumulate(data, max))
print(f"元のデータ: {data}")
print(f"累積最大値: {cumulative_max}")
# 実践例:売上の累積計算
print("\n月次売上の累積:")
monthly_sales = [100, 150, 120, 200, 180]
months = ['1月', '2月', '3月', '4月', '5月']
cumulative_sales = list(accumulate(monthly_sales))
for month, monthly, cumulative in zip(months, monthly_sales, cumulative_sales):
print(f"{month}: 月次 {monthly}万円, 累積 {cumulative}万円")
# 初期値の設定
print("\n初期値ありの累積和:")
initial_value = 100
result = list(accumulate(numbers, initial=initial_value))
print(f"初期値 {initial_value} からの累積: {result}")
出力結果:
累積和:
元の数値: [1, 2, 3, 4, 5]
累積和: [1, 3, 6, 10, 15]
累積積:
累積積: [1, 2, 6, 24, 120]
累積最大値:
元のデータ: [3, 1, 4, 1, 5, 9, 2, 6]
累積最大値: [3, 3, 4, 4, 5, 9, 9, 9]
月次売上の累積:
1月: 月次 100万円, 累積 100万円
2月: 月次 150万円, 累積 250万円
3月: 月次 120万円, 累積 370万円
4月: 月次 200万円, 累積 570万円
5月: 月次 180万円, 累積 750万円
初期値ありの累積和:
初期値 100 からの累積: [100, 101, 103, 106, 110, 115]
groupby():グループ化
同じキーを持つ連続する要素をグループ化します。
基本構文:
itertools.groupby(iterable, key=None)
重要な注意点: groupby()は連続する同じ値のみをグループ化します。事前にソートが必要な場合があります。
実用例:
from itertools import groupby
from operator import itemgetter
# 基本的な使用例(連続する同じ値のグループ化)
data = [1, 1, 2, 2, 2, 3, 1, 1]
print("連続する同じ値のグループ化:")
for key, group in groupby(data):
items = list(group)
print(f"値 {key}: {items} (個数: {len(items)})")
# 実践例:学生の成績データのグループ化
students = [
('Alice', 'A'),
('Bob', 'B'),
('Charlie', 'A'),
('David', 'B'),
('Eve', 'A'),
('Frank', 'C')
]
# 成績でソートしてからグループ化
students_sorted = sorted(students, key=itemgetter(1))
print("\n成績別のグループ化:")
for grade, group in groupby(students_sorted, key=itemgetter(1)):
students_in_grade = list(group)
names = [student[0] for student in students_in_grade]
print(f"成績 {grade}: {names}")
# 文字列の連続文字のグループ化
text = "aaabbccccaaa"
print("\n連続する文字のグループ化:")
for char, group in groupby(text):
count = len(list(group))
print(f"'{char}' が {count} 個連続")
# 実践例:ログデータの日付別グループ化
import datetime
log_data = [
('2024-01-01', 'INFO', 'System started'),
('2024-01-01', 'ERROR', 'Connection failed'),
('2024-01-01', 'INFO', 'Connection restored'),
('2024-01-02', 'INFO', 'Daily backup'),
('2024-01-02', 'WARNING', 'Low disk space'),
('2024-01-03', 'INFO', 'System updated')
]
print("\n日付別ログのグループ化:")
for date, group in groupby(log_data, key=itemgetter(0)):
logs = list(group)
print(f"\n{date} ({len(logs)}件):")
for log in logs:
print(f" {log[1]}: {log[2]}")
出力結果:
連続する同じ値のグループ化:
値 1: [1, 1] (個数: 2)
値 2: [2, 2, 2] (個数: 3)
値 3: [3] (個数: 1)
値 1: [1, 1] (個数: 2)
成績別のグループ化:
成績 A: ['Alice', 'Charlie', 'Eve']
成績 B: ['Bob', 'David']
成績 C: ['Frank']
連続する文字のグループ化:
'a' が 3 個連続
'b' が 2 個連続
'c' が 4 個連続
'a' が 3 個連続
日付別ログのグループ化:
2024-01-01 (3件):
INFO: System started
ERROR: Connection failed
INFO: Connection restored
2024-01-02 (2件):
INFO: Daily backup
WARNING: Low disk space
2024-01-03 (1件):
INFO: System updated
フィルタ・選択関数群

takewhile()とdropwhile():条件付き要素の取得
takewhile(): 条件が真の間だけ要素を取得 dropwhile(): 条件が偽になるまで要素をスキップ
実用例:
from itertools import takewhile, dropwhile
# 基本的な使用例
numbers = [1, 3, 5, 8, 9, 11, 12, 15]
# 10未満の間だけ取得
print("takewhile - 10未満の間だけ取得:")
result1 = list(takewhile(lambda x: x < 10, numbers))
print(f"元のデータ: {numbers}")
print(f"結果: {result1}")
# 10未満の間はスキップ
print("\ndropwhile - 10未満の間はスキップ:")
result2 = list(dropwhile(lambda x: x < 10, numbers))
print(f"結果: {result2}")
# 実践例:ログファイルから特定期間のデータを抽出
log_entries = [
"2024-01-01 09:00 System start",
"2024-01-01 09:15 User login",
"2024-01-01 10:00 Error occurred",
"2024-01-01 10:30 Error resolved",
"2024-01-01 11:00 Normal operation",
"2024-01-01 11:30 User logout"
]
# 10時以降のログを取得
print("\n10時以降のログエントリ:")
morning_logs = list(dropwhile(
lambda log: "10:" not in log,
log_entries
))
for log in morning_logs:
print(f" {log}")
# エラーが発生するまでのログを取得
print("\nエラー発生前のログ:")
pre_error_logs = list(takewhile(
lambda log: "Error" not in log,
log_entries
))
for log in pre_error_logs:
print(f" {log}")
出力結果:
takewhile - 10未満の間だけ取得:
元のデータ: [1, 3, 5, 8, 9, 11, 12, 15]
結果: [1, 3, 5, 8, 9]
dropwhile - 10未満の間はスキップ:
結果: [11, 12, 15]
10時以降のログエントリ:
2024-01-01 10:00 Error occurred
2024-01-01 10:30 Error resolved
2024-01-01 11:00 Normal operation
2024-01-01 11:30 User logout
エラー発生前のログ:
2024-01-01 09:00 System start
2024-01-01 09:15 User login
filterfalse():条件に合わない要素のフィルタ
通常のfilter()とは逆で、条件に合わない要素を取得します。
実用例:
from itertools import filterfalse
# 基本的な使用例
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 偶数ではない数値(奇数)を取得
odd_numbers = list(filterfalse(lambda x: x % 2 == 0, numbers))
print(f"奇数: {odd_numbers}")
# 実践例:不正なデータを除外
user_data = [
{"name": "Alice", "age": 25},
{"name": "", "age": 30}, # 名前が空
{"name": "Bob", "age": -5}, # 年齢が負数
{"name": "Charlie", "age": 35},
{"name": "David", "age": 0} # 年齢が0
]
def is_valid_user(user):
return user["name"] and user["age"] > 0
# 無効なユーザーデータを取得
invalid_users = list(filterfalse(is_valid_user, user_data))
print(f"\n無効なユーザーデータ:")
for user in invalid_users:
print(f" {user}")
# 有効なユーザーデータ(比較用)
valid_users = list(filter(is_valid_user, user_data))
print(f"\n有効なユーザーデータ:")
for user in valid_users:
print(f" {user}")
出力結果:
奇数: [1, 3, 5, 7, 9]
無効なユーザーデータ:
{'name': '', 'age': 30}
{'name': 'Bob', 'age': -5}
{'name': 'David', 'age': 0}
有効なユーザーデータ:
{'name': 'Alice', 'age': 25}
{'name': 'Charlie', 'age': 35}
実践的な応用例
データ処理での活用
CSVデータの効率的な処理:
from itertools import groupby, accumulate
import csv
from io import StringIO
# サンプルCSVデータ
csv_data = """date,product,sales
2024-01-01,A,100
2024-01-01,B,150
2024-01-01,A,80
2024-01-02,A,120
2024-01-02,B,200
2024-01-02,C,90"""
# CSVデータの読み込みと処理
reader = csv.DictReader(StringIO(csv_data))
data = list(reader)
# 日付でソートしてグループ化
data_sorted = sorted(data, key=lambda x: x['date'])
print("日付別売上サマリー:")
for date, group in groupby(data_sorted, key=lambda x: x['date']):
daily_sales = [int(item['sales']) for item in group]
total_sales = sum(daily_sales)
products = len(daily_sales)
print(f"{date}: {products}商品, 合計 {total_sales}")
# 累積売上の計算
all_sales = [int(item['sales']) for item in data]
cumulative_sales = list(accumulate(all_sales))
print(f"\n売上推移: {all_sales}")
print(f"累積売上: {cumulative_sales}")
Webスクレイピングでの活用
URLの組み合わせ生成:
from itertools import product
# 複数のページを効率的にスクレイピング
base_url = "https://example.com"
categories = ['electronics', 'books', 'clothing']
pages = range(1, 4) # 1-3ページ
print("スクレイピング対象URL:")
for category, page in product(categories, pages):
url = f"{base_url}/{category}?page={page}"
print(f" {url}")
# 検索パラメータの組み合わせ
search_terms = ['python', 'programming']
sort_options = ['date', 'popularity', 'price']
filters = ['new', 'used']
print(f"\n検索パラメータの組み合わせ(全{len(search_terms) * len(sort_options) * len(filters)}通り):")
for i, (term, sort, filter_type) in enumerate(product(search_terms, sort_options, filters)):
if i >= 6: # 最初の6つのみ表示
break
params = f"q={term}&sort={sort}&filter={filter_type}"
print(f" {params}")
ゲーム開発での活用
カードゲームのデッキ生成:
from itertools import product, combinations, cycle
# トランプのデッキ生成
suits = ['♠', '♥', '♦', '♣']
ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
# 全てのカードを生成
deck = list(product(suits, ranks))
print(f"デッキ総数: {len(deck)}枚")
print("最初の10枚:")
for i, (suit, rank) in enumerate(deck[:10]):
print(f" {suit}{rank}")
# ポーカーハンドの組み合わせ(5枚)
print(f"\nポーカーハンドの総組み合わせ数: {len(list(combinations(deck, 5)))} 通り")
# プレイヤーのターン管理
players = ['Player1', 'Player2', 'Player3', 'Player4']
turn_cycle = cycle(players)
print(f"\nターン順(10ターン分):")
for turn in range(10):
current_player = next(turn_cycle)
print(f" ターン {turn + 1}: {current_player}")
アルゴリズム問題の解決
最適化問題の例:
from itertools import permutations, combinations
# 巡回セールスマン問題の簡単な例
cities = ['A', 'B', 'C', 'D']
distances = {
('A', 'B'): 10, ('A', 'C'): 15, ('A', 'D'): 20,
('B', 'A'): 10, ('B', 'C'): 35, ('B', 'D'): 25,
('C', 'A'): 15, ('C', 'B'): 35, ('C', 'D'): 30,
('D', 'A'): 20, ('D', 'B'): 25, ('D', 'C'): 30
}
def calculate_route_distance(route):
"""ルートの総距離を計算"""
total = 0
for i in range(len(route)):
from_city = route[i]
to_city = route[(i + 1) % len(route)] # 最後は出発点に戻る
total += distances.get((from_city, to_city), float('inf'))
return total
# 全ての可能なルートを検証
print("巡回セールスマン問題の最適解:")
best_route = None
best_distance = float('inf')
for route in permutations(cities):
distance = calculate_route_distance(route)
if distance < best_distance:
best_distance = distance
best_route = route
print(f"最適ルート: {' → '.join(best_route)} → {best_route[0]}")
print(f"総距離: {best_distance}")
# ナップサック問題の例(組み合わせ最適化)
items = [
('本', 2, 3), # (名前, 重さ, 価値)
('水', 3, 1),
('食料', 1, 4),
('服', 4, 2),
('工具', 5, 5)
]
capacity = 8
print(f"\nナップサック問題(容量: {capacity}):")
best_value = 0
best_combination = []
# 全ての組み合わせを試す
for r in range(1, len(items) + 1):
for combo in combinations(items, r):
total_weight = sum(item[1] for item in combo)
total_value = sum(item[2] for item in combo)
if total_weight <= capacity and total_value > best_value:
best_value = total_value
best_combination = combo
print(f"最適な組み合わせ:")
for item in best_combination:
print(f" {item[0]} (重さ: {item[1]}, 価値: {item[2]})")
print(f"総重量: {sum(item[1] for item in best_combination)}")
print(f"総価値: {best_value}")
パフォーマンス最適化とメモリ効率

メモリ使用量の比較
import sys
from itertools import count, repeat
def memory_comparison():
"""リストとイテレータのメモリ使用量比較"""
# 大きなリスト
large_list = list(range(100000))
list_memory = sys.getsizeof(large_list)
# イテレータ
large_iterator = count()
iterator_memory = sys.getsizeof(large_iterator)
print("メモリ使用量の比較:")
print(f"リスト(100,000要素): {list_memory:,} bytes")
print(f"イテレータ: {iterator_memory:,} bytes")
print(f"メモリ節約率: {((list_memory - iterator_memory) / list_memory * 100):.1f}%")
memory_comparison()
# 実際の処理時間比較
import time
def timing_comparison():
"""処理時間の比較"""
# リスト内包表記
start_time = time.time()
result1 = [x**2 for x in range(100000)]
list_time = time.time() - start_time
# ジェネレータ式
start_time = time.time()
result2 = (x**2 for x in range(100000))
# 実際に使用する際の時間(最初の10個のみ)
first_10 = [next(result2) for _ in range(10)]
generator_time = time.time() - start_time
print(f"\n処理時間の比較:")
print(f"リスト内包表記: {list_time:.4f}秒")
print(f"ジェネレータ式: {generator_time:.4f}秒")
timing_comparison()
大量データの効率的な処理
from itertools import islice, chain
def process_large_file_efficiently(filename="large_data.txt"):
"""大量データファイルの効率的な処理例"""
# サンプルデータの作成(実際のファイルがない場合)
sample_data = [f"line_{i}: data_{i}\n" for i in range(1000)]
def data_generator():
"""データを一行ずつ生成するジェネレータ"""
for line in sample_data:
yield line.strip()
# バッチ処理の例
def process_in_batches(data_gen, batch_size=100):
"""データをバッチごとに処理"""
iterator = iter(data_gen())
while True:
batch = list(islice(iterator, batch_size))
if not batch:
break
# バッチ処理の実行
processed_count = len([line for line in batch if 'data' in line])
print(f"バッチ処理完了: {len(batch)}行中 {processed_count}行を処理")
print("大量データの効率的な処理:")
process_in_batches(data_generator)
process_large_file_efficiently()
# 複数データソースの結合
def combine_data_sources():
"""複数のデータソースを効率的に結合"""
# 複数のデータソース
source1 = range(1, 6) # [1, 2, 3, 4, 5]
source2 = range(10, 16) # [10, 11, 12, 13, 14, 15]
source3 = range(20, 26) # [20, 21, 22, 23, 24, 25]
# chain()を使用した効率的な結合
combined = chain(source1, source2, source3)
print(f"\n複数データソースの結合:")
print(f"結合結果: {list(combined)}")
# 実際の使用例:ログファイルの結合処理
def log_generator(prefix, count):
for i in range(count):
yield f"{prefix}_log_{i}"
# 複数のログファイルを順次処理
all_logs = chain(
log_generator("system", 3),
log_generator("error", 2),
log_generator("access", 4)
)
print(f"ログファイル結合:")
for log in all_logs:
print(f" {log}")
combine_data_sources()
よくあるパターンとベストプラクティス
エラーハンドリングと例外処理
from itertools import count, takewhile
import random
def safe_iterator_usage():
"""安全なイテレータ使用のパターン"""
# 無限イテレータの安全な使用
def safe_infinite_loop():
counter = count(1)
max_iterations = 1000 # 安全装置
for i, value in enumerate(counter):
if i >= max_iterations:
print("安全装置作動: 最大反復回数に達しました")
break
# ランダムな条件で終了
if random.random() < 0.01: # 1%の確率で終了
print(f"条件達成で終了: {value}")
break
else:
print("正常終了")
print("安全な無限ループの例:")
safe_infinite_loop()
# エラー処理を含むイテレータ使用
def process_with_error_handling(data):
"""エラーハンドリング付きの処理"""
for item in data:
try:
# 何らかの処理(エラーが発生する可能性)
if item == 'error':
raise ValueError(f"エラーアイテム: {item}")
result = item.upper()
yield result
except ValueError as e:
print(f"警告: {e} - スキップします")
continue
except Exception as e:
print(f"予期しないエラー: {e} - 処理を中断")
break
test_data = ['hello', 'world', 'error', 'python', 'itertools']
print(f"\nエラーハンドリング付き処理:")
processed = list(process_with_error_handling(test_data))
print(f"処理結果: {processed}")
safe_iterator_usage()
デバッグとプロファイリング
from itertools import count, accumulate
import time
def debug_itertools():
"""itertoolsのデバッグテクニック"""
def debug_wrapper(iterator, name="Iterator"):
"""イテレータをラップしてデバッグ情報を出力"""
count = 0
for item in iterator:
count += 1
print(f"[{name}] {count}: {item}")
yield item
# デバッグ情報付きのイテレータ使用
print("デバッグ情報付きイテレータ:")
numbers = range(1, 6)
debugged_accumulate = debug_wrapper(
accumulate(numbers),
"Accumulate"
)
result = list(debugged_accumulate)
print(f"最終結果: {result}")
# パフォーマンス測定
def measure_performance(func, name, *args):
"""関数の実行時間を測定"""
start_time = time.time()
result = func(*args)
end_time = time.time()
# イテレータの場合は実際に消費する
if hasattr(result, '__iter__') and not isinstance(result, (list, tuple, str)):
result = list(result)
execution_time = end_time - start_time
print(f"{name}: {execution_time:.6f}秒")
return result
print(f"\nパフォーマンス測定:")
data = range(10000)
# 異なる方法での累積和計算
def list_comprehension_cumsum(data):
result = []
total = 0
for x in data:
total += x
result.append(total)
return result
def itertools_cumsum(data):
return accumulate(data)
result1 = measure_performance(list_comprehension_cumsum, "手動累積計算", data)
result2 = measure_performance(itertools_cumsum, "itertools.accumulate", data)
print(f"結果一致: {list(result1) == list(result2)}")
debug_itertools()
他ライブラリとの連携
NumPyとの連携
try:
import numpy as np
from itertools import product, combinations
def numpy_itertools_integration():
"""NumPyとitertoolsの連携例"""
# グリッド座標の生成
x_coords = range(3)
y_coords = range(3)
# itertoolsで座標生成
coordinates = list(product(x_coords, y_coords))
print("グリッド座標:")
for coord in coordinates:
print(f" {coord}")
# NumPy配列として利用
coord_array = np.array(coordinates)
print(f"\nNumPy配列形状: {coord_array.shape}")
print(f"座標配列:\n{coord_array}")
# 距離計算の例
def calculate_distances(coords):
"""各座標間の距離を計算"""
distances = []
for coord1, coord2 in combinations(coords, 2):
dist = np.linalg.norm(np.array(coord1) - np.array(coord2))
distances.append(dist)
return distances
distances = calculate_distances(coordinates)
print(f"\n座標間距離(最初の5つ): {distances[:5]}")
numpy_itertools_integration()
except ImportError:
print("NumPyがインストールされていません")
pandasとの連携
try:
import pandas as pd
from itertools import product, groupby
def pandas_itertools_integration():
"""pandasとitertoolsの連携例"""
# 実験データの生成
conditions = ['A', 'B']
replicates = range(1, 4)
measurements = [10, 15, 12, 18, 14, 16]
# 全組み合わせのデータフレーム作成
experiment_design = list(product(conditions, replicates))
df = pd.DataFrame({
'condition': [x[0] for x in experiment_design],
'replicate': [x[1] for x in experiment_design],
'measurement': measurements
})
print("実験データ:")
print(df)
# itertoolsでグループ化してからpandasで集計
df_sorted = df.sort_values(['condition', 'replicate'])
print(f"\n条件別統計:")
for condition, group_df in df.groupby('condition'):
measurements = group_df['measurement'].tolist()
print(f"条件 {condition}: 平均 {np.mean(measurements):.1f}, 標準偏差 {np.std(measurements):.1f}")
pandas_itertools_integration()
except ImportError:
print("pandasがインストールされていません")
まとめz
itertoolsは、Pythonで繰り返し処理をスマートに書きたいときにとても強力なモジュールです。
覚えると「わざわざループを書かなくても一発でできる」ことが増え、コードの読みやすさ・速度・効率すべてがアップします。
この記事をブックマークして、ぜひプロジェクトや日々のツール作成に活用してみてください。
重要なポイント:
✅ メモリ効率:大量データも少ないメモリで処理
✅ 高速処理:C言語レベルで最適化された実装
✅ 簡潔な記述:複雑なループを1行で表現
✅ 組み合わせ:他のライブラリとの強力な連携


コメント