k
最初のn
自然数の組み合わせを考えると、何らかの理由で、によって返されるものの中からそのような組み合わせの位置を見つける必要がありますitertools.combination(range(1,n),k)
(この方法では、のlist
代わりにを使用しdict
て、各組み合わせに関連付けられた値にアクセスできます。組み合わせ)。
規則的なパターンでその組み合わせを生成するのでitertools
、それを行うことは可能です(そして私はまたきちんとしたアルゴリズムを見つけました)が、私は無視するかもしれないさらに速く/自然な方法を探しています。
ちなみにここに私の解決策があります:
def find_idx(comb,n):
k=len(comb)
idx=0
last_c=0
for c in comb:
#idx+=sum(nck(n-2-x,k-1) for x in range(c-last_c-1)) # a little faster without nck caching
idx+=nck(n-1,k)-nck(n-c+last_c,k) # more elegant (thanks to Ray), faster with nck caching
n-=c-last_c
k-=1
last_c=c
return idx
ここで、n、kの二項係数をnck
返します。
例えば:
comb=list(itertools.combinations(range(1,14),6))[654] #pick the 654th combination
find_idx(comb,14) # -> 654
そして、これは同等ですが、おそらくそれほど複雑ではないバージョンです(実際には、前のバージョンを次のバージョンから派生させました)。組み合わせの整数をc
2進数の1の位置と見なし、0/1の解析でバイナリツリーを構築し、解析中にインデックス増分の規則的なパターンを見つけました。
def find_idx(comb,n):
k=len(comb)
b=bin(sum(1<<(x-1) for x in comb))[2:]
idx=0
for s in b[::-1]:
if s=='0':
idx+=nck(n-2,k-1)
else:
k-=1
n-=1
return idx