Pythonの標準ライブラリitertools
は、順列や組み合わせといった操作を効率的に行うための機能を提供しています。その中でも、重複を許可しつつ順不同の組み合わせを生成するcombinations_with_replacement
は、特に便利なツールの一つです。
この記事では、この関数の基本的な使い方から応用例まで詳しく解説します。
combinations_with_replacementとは?
combinations_with_replacement
は、重複を許可しながら、順不同の組み合わせを生成するための関数です。以下のように使います:
from itertools import combinations_with_replacement
combinations_with_replacement(iterable, r)
- iterable: 入力データ(リスト、文字列、タプルなど)。
- r: 組み合わせの長さ。
この関数のポイントは、同じ要素を複数回選べることと、**順序を気にしない(辞書順で結果が得られる)**ことです。
基本的な使用例
まずは、基本的な使い方から見てみましょう。
from itertools import combinations_with_replacement
data = ['A', 'B', 'C']
result = combinations_with_replacement(data, 2)
print(list(result))
このコードは、['A', 'B', 'C']
から2つの要素を選ぶ全ての組み合わせを生成します。結果は以下のようになります:
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')]
数値を使った応用例
リストに数値が含まれる場合も同様に使えます。例えば、以下のコードでは3つの要素を選ぶ組み合わせを生成します:
from itertools import combinations_with_replacement
numbers = [1, 2, 3]
result = combinations_with_replacement(numbers, 3)
print(list(result))
結果は次の通りです:
[(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 2), (1, 2, 3), (1, 3, 3), (2, 2, 2), (2, 2, 3), (2, 3, 3), (3, 3, 3)]
フィルタリングを活用したカスタム条件の例
生成された組み合わせに条件を追加してフィルタリングすることも可能です。例えば、組み合わせの合計が特定の値以下になるように制限する場合は次のように書けます:
from itertools import combinations_with_replacement
data = [1, 2, 3]
result = combinations_with_replacement(data, 3)
# 合計が5以下の組み合わせを取得
filtered_result = [comb for comb in result if sum(comb) <= 5]
print(filtered_result)
このコードは、合計が5以下の組み合わせだけを抽出します。出力は次の通りです:
[(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 2), (1, 2, 3), (2, 2, 2)]
無限イテラブルとの組み合わせ
combinations_with_replacement
は無限イテラブルとも組み合わせて使用できます。例えば、自然数を生成する無限イテラブルcount
を利用して、最初の10個の組み合わせを取得する例を見てみましょう:
from itertools import combinations_with_replacement, islice, count
# 無限イテラブルを準備
infinite_numbers = count(1)
# 最初の10個の組み合わせを取得
limited_result = islice(combinations_with_replacement(infinite_numbers, 2), 10)
print(list(limited_result))
このコードは、次のような結果を生成します:
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10)]
無限イテラブルを使う際には、islice
のような制限を設けることを忘れないでください。制限しないと無限ループに陥る危険があります。
現実的なユースケース
硬貨の支払いパターン
例えば、硬貨(10円、50円、100円)を使って特定の金額を支払う方法を計算する際に使えます。
from itertools import combinations_with_replacement
coins = [10, 50, 100]
result = combinations_with_replacement(coins, 3)
for combination in result:
print(f"組み合わせ: {combination}, 合計: {sum(combination)}")
ダイスの目の列挙
サイコロを複数回振った結果を列挙したい場合にも有用です。
from itertools import combinations_with_replacement
dice_faces = [1, 2, 3, 4, 5, 6]
result = combinations_with_replacement(dice_faces, 2)
print(list(result))
これにより、ダイスを2回振ったときの全ての目の組み合わせが生成されます。
注意点
- 組み合わせの総数: 組み合わせの長さ
r
が大きくなると生成される組み合わせ数が急激に増えるため、計算コストやメモリ使用量に注意が必要です。 - 無限イテラブル: 無限イテラブルを使用する場合は、
islice
などで結果を制限する工夫を必ず行いましょう。
まとめ
combinations_with_replacement
は、重複を許可した組み合わせを簡単に生成できる便利な関数です。数学的な組み合わせの列挙からシミュレーションまで、幅広い場面で活用できます。
ぜひ、自分のプロジェクトに取り入れてみてください!