itertoolsを使えば順列 / 組み合わせ / 重複順列 / 重複組み合わせは簡単にできるけど、自前でやったらどうなるんだろ?ということでやってみました。
JSでやった過去記事の焼き直しです。よりPythonっぽく?やってみました。
# 共通部分:
def permcombi_gen(filter_f):
def inner1(confirmeds):
def inner2(k):
def inner3(options):
if k == 0:
yield confirmeds
else :
for i in range(len(options)):
yield from permcombi_gen(filter_f)(
(*confirmeds, options[i])
)(k - 1)( filter_f(i)(options) )
return inner3
return inner2
return inner1
# 各filter_f:
perm_f = lambda i: lambda options: (
*options[:i]
, *options[i+1:]
)
combi_f = lambda i: lambda options: options[i+1:]
repperm_f = lambda _: lambda options: options
repcombi_f = lambda i: lambda options: options[i:]
# 各ジェネレータ:
perm = permcombi_gen(perm_f)(())
combi = permcombi_gen(combi_f)(())
repperm = permcombi_gen(repperm_f)(())
repcombi = permcombi_gen(repcombi_f)(())
# 使用例:
xs = (0, 1, 2)
r = 2
print("perm:")
for e in perm(r)(xs):
print(e)
print("combi:")
for e in combi(r)(xs):
print(e)
print("repperm:")
for e in repperm(r)(xs):
print(e)
print("repcombi:")
for e in repcombi(r)(xs):
print(e)
やってることは
- 数が揃ったら 確定枠 confirmeds を yield する
- まだ揃ってなかったら、
- すべての候補 options について
- 確定枠に候補をひとつ移動して
- カウンタ k をひとつ減らして
- 新しく 候補を計算して
- それらを使って再帰的に計算して yield する
- すべての候補 options について
って感じです(inner3 のあたり)。
順列 / 組み合わせ / 重複順列 / 重複組み合わせ によって次回の候補が異ってくるので、個別に定義しました。
あとは各filter_fと confirmeds の初期値 (空のタプル)を部分適用したら各ジェネレーターになります。