Python | データ構造強化:itertools.combinations

Python Python
スポンサーリンク

概要(combinations は「順番を無視した取り合わせ」を遅延生成する)

itertools.combinations は、イテラブルから要素を r 個選ぶすべての“組み合わせ”を順に返すイテレータです。順番は意味を持たず、同じ要素の並びは一度だけ出ます(例:(“A”,”B”) と (“B”,”A”) は同じ組み合わせなので片方だけ)。結果はメモリに一括展開せず、必要な分だけ取り出せるため大きなデータでも安全です。

from itertools import combinations

items = ["A", "B", "C"]
for comb in combinations(items, 2):
    print(comb)  # ('A','B'), ('A','C'), ('B','C')
Python

基本の使い方(ここが重要)

r 個を選ぶ組み合わせ(順序は無視される)

r は選ぶ個数です。r を増やすほど通り数が増えますが、順序を無視するため重複した並びは出ません。

from itertools import combinations

print(list(combinations([1,2,3], 2)))  # [(1,2),(1,3),(2,3)]
print(list(combinations("ABC", 3)))    # [('A','B','C')]
Python

返り値はタプル。必要なら整形して使う

用途に応じて文字列連結や計算へ変換します。

from itertools import combinations

for comb in combinations("ABCD", 2):
    print("".join(comb))  # 'AB','AC','AD','BC','BD','CD'
Python

遅延生成(巨大でも安全。全展開は慎重に)

for で流せば一組ずつ生成されます。list(…) で全部を作るとメモリを使うため、必要な範囲に留めるのが基本です。

from itertools import combinations, islice

it = combinations(range(1000), 3)
for c in islice(it, 5):   # 先頭5件だけ確認
    print(c)
Python

重要ポイントの深掘り(通り数・重複要素・境界条件)

通り数は nCr(組合せ)。サイズ見積りを意識する

元の要素数を n、選ぶ数を r とすると、通り数は nCr です。n や r が増えると急増するため、事前見積りと絞り込み条件が重要です。

import math

n, r = 10, 3
print(math.comb(n, r))  # 120(10C3)
Python

入力に重複値があると「同じ値を含む組み合わせ」が増える

combinations は位置ではなく値で重複を抑えるわけではありません。入力に同じ値が複数あると、値が同じでも位置が異なる要素から組が作られます。値ベースでユニーク化したいなら、事前に集合化やソート+重複除去を行います。

from itertools import combinations

items = ["A","A","B"]
print(list(combinations(items, 2)))  # [('A','A'), ('A','B'), ('A','B')]
# 値でユニーク化したいなら事前に set などで重複除去
Python

r の境界条件(r=0、r>n)の扱い

r=0 のときは「空タプル一つ」(なにも選ばないという1通り)が返ります。r>n のときは通り数ゼロです。

from itertools import combinations

print(list(combinations([1,2,3], 0)))  # [()]
print(list(combinations([1,2], 3)))    # []
Python

実務での使いどころ(選定・検証・探索の“母集団づくり”)

上位候補の組み合わせ評価(スコアで絞り込む)

まず全組み合わせを生成し、評価関数で上位を選ぶのが定石です。遅延生成なので、スコアが低いものは早めに捨てられます。

from itertools import combinations

items = [("coffee", 92), ("tea", 81), ("sugar", 75)]
def score(combo):
    return sum(v for _, v in combo)

best = None
best_score = -1
for comb in combinations(items, 2):
    s = score(comb)
    if s > best_score:
        best, best_score = comb, s

print(best, best_score)  # 上位2品の組み合わせ
Python

機能フラグの同時有効パターン検証

フラグを複数同時に立てた時だけ現れる不具合を探るとき、r 個同時オンの全通りでテストできます。

from itertools import combinations

flags = ["A","B","C","D"]
for enabled in combinations(flags, 3):
    print("enable:", enabled)  # 3つ同時オンの全通り
Python

部分選択の探索(予算内・容量内のフィルタ)

組み合わせを生成しながら、条件で早期フィルタすることで現実的な探索に落とせます。

from itertools import combinations

items = [("A", 50), ("B", 40), ("C", 30), ("D", 20)]
budget = 70
for comb in combinations(items, 2):
    cost = sum(c for _, c in comb)
    if cost <= budget:
        print(comb, cost)
Python

関連関数との使い分け(順列・直積・重複許可)

permutations(順番あり)との違い

permutations は順序を区別します。(“A”,”B”) と (“B”,”A”) は別。並び順が意味を持つならこちらを選びます。組み合わせは順序が無関係です。

from itertools import permutations

print(list(permutations(["A","B"], 2)))  # [('A','B'),('B','A')]
Python

product(直積)との違い

product は別集合同士の全通り(r 回重複選択も可能)。「同じ集合から r 個選ぶ」なら combinations/permutations が自然です。

from itertools import product

print(list(product(["A","B"], [1,2])))  # [('A',1),('A',2),('B',1),('B',2)]
Python

combinations_with_replacement(重複選択を許す組み合わせ)

同じ要素を複数回選ぶ組み合わせが欲しいときに使います。例:硬貨の選び方など。

from itertools import combinations_with_replacement

print(list(combinations_with_replacement([1,2,3], 2)))
# [(1,1),(1,2),(1,3),(2,2),(2,3),(3,3)]
Python

例題で身につける(定番から一歩先まで)

例題1:上位 N 件の組み合わせを部分取得

from itertools import combinations, islice

items = ["coffee","tea","sugar","milk"]
for comb in islice(combinations(items, 3), 5):  # 先頭5通りだけ
    print(comb)
Python

例題2:CSV の列からペアを作り、相関候補を列挙

from itertools import combinations

cols = ["temp","sales","visitors","cost"]
pairs = list(combinations(cols, 2))
print(pairs)  # すべての指標ペア
Python

例題3:座標の組み合わせで三角形候補を生成し、面積でフィルタ

from itertools import combinations

points = [(0,0),(1,0),(0,1),(1,1)]
def area(p,q,r):
    return abs((p[0]*(q[1]-r[1])+q[0]*(r[1]-p[1])+r[0]*(p[1]-q[1]))/2)

for tri in combinations(points, 3):
    if area(*tri) > 0:  # 面積ゼロ(一直線)を除外
        print(tri)
Python

例題4:文字列から重複のない部分文字列候補を生成

from itertools import combinations

s = "ABCD"
subs = ["".join(s[i] for i in idxs) for r in range(1, len(s)+1) for idxs in combinations(range(len(s)), r)]
print(subs)  # 'A','B','C','D','AB','AC', ... 'ABCD'
Python

まとめ

itertools.combinations は「順番を無視した取り合わせ」を遅延生成で安全に列挙するための基本ツールです。通り数は nCr で急増するため、サイズ見積りと早期フィルタが重要。返り値はタプルで、文字列連結や計算へ柔軟に変換できる。入力の重複値はそのまま反映されるため、値ベースのユニーク化が必要なら事前処理を行う。permutations(順番あり)、product(直積)、combinations_with_replacement(重複許可)と正しく使い分ければ、選定・検証・探索の母集団作りが短く、読みやすく、堅牢に書けます。

タイトルとURLをコピーしました