Python-获取组合的索引

Python-获取组合的索引,python,loops,Python,Loops,例如,我需要生成从“a”到“]]]]]的组合,为了实现这一点,我使用了这个python脚本,它工作得很好 import itertools DATA_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&- ()@=+;/!%$\\'\",.<>*^{}#~_[]" b = 10 for i in range(1,int(b)+1): for e in itertoo

例如,我需要生成从“a”到“]]]]]的组合,为了实现这一点,我使用了这个python脚本,它工作得很好

import itertools

DATA_ALPHA_NUM = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&-
()@=+;/!%$\\'\",.<>*^{}#~_[]"
b = 10

for i in range(1,int(b)+1):
   for e in itertools.combinations(DATA_ALPHA_NUM,i): print(''.join(e))
概述 关键是遍历累积组合,直到达到索引

解决方案 还有另一种方法可以完全避免大的阶乘,并且不需要辅助存储:

def comb(n, r):
    c = 1
    r = min(r, n-r)
    for i in range(1, r+1):
        c = c * (n - r + i) // i
    return c
工作原理 首先,将组合分解为其组件组:

def groups(n, r):
    return [comb(n-i-1, r-1) for i in range(n-r+1)]

>>> comb(8, 3)
56
>>> groups(8, 3)
[21, 15, 10, 6, 3, 1]
这意味着,当您一次为
n=8
字母
r=3
运行
itertools.compositions('ABCDEFGH',3)
时,有56个组合。前21个以
A
开头,下15个以
B
开头,下10个以
C
开头,下6个以
D
开头,下3个以
E
开头,最后1个以
F
开头

假设你想从56个组合中找出第25个组合。这属于第二组,因此您的第一个字母是
B

因为25-21是4,所以您需要在由
itertools.combines('CDEFGH',2)
定义的“B”组的15个成员中找到第4个组合。只要重复上述过程,直到所有的字母都被提取出来

测试 下面是一个测试,以确保它提供了预期的结果:

from itertools import combinations

population = 'ABCDEFGH'
for r in range(len(population) + 1):
    for i, expected in enumerate(combinations(population, r)):
        actual = locate(list(population), r, i)
        assert expected == actual

你不想要组合。事实上,你想要“aa”。但对于组合,因为你从来不会选择两次相同的项目,这不会发生

因此,这里有一个“累积积”的正确版本,实际上,就像雷蒙德对组合所做的那样,我必须计数(90,90+90**2,90+90**2+90**3,…),以找到与我正在跟踪的组合相对应的最佳功率

请注意,它并没有优化,因为我在切割产品。。。只是为了检索一个值

import itertools

alphaNumList = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&-()@=+;/!%$\\'\",.<>*^{}#~_[]")

cumulative = [len(alphaNumList)]
for i in range(1, 10):
    cumulative.append(len(alphaNumList) ** (i+1) + cumulative[i - 1])


def getCombiFromIndex(combiNumber):
    p = 0
    while cumulative[p] < combiNumber:
        p += 1  # WARNING : not robust to combi greater than (10,90) in my case :)
    rest = combiNumber - 1 - (cumulative[p - 1] if p > 0 else 0)
    return "".join([item for item in itertools.islice(itertools.product(alphaNumList, repeat=p + 1), rest, rest + 1)][0])


print(getCombiFromIndex(1))  # "a"
print(getCombiFromIndex(90))  # "]"
print(getCombiFromIndex(91))  # "aa"
print(getCombiFromIndex(800064))  # "ah+1"
导入itertools
alphaNumList=list(“abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzo123456789&-()@=+;/!%$\'\”,.*
累积=[len(alphaNumList)]
对于范围(1,10)内的i:
累计。追加(len(alphaNumList)**(i+1)+累计[i-1])
def getCombiFromIndex(组合编号):
p=0
当累积[p]0,则累积[p-1],否则为0)
return”“.join([itertools.islice(itertools.product(alphaNumList,repeat=p+1),rest,rest+1)中的项对应项][0])
打印(getCombiFromIndex(1))#“a”
打印(getCombiFromIndex(90))#“]
打印(getCombiFromIndex(91))#“aa”
打印(getCombiFromIndex(800064))#“ah+1”
更新:基于相同的概念,我添加了在两个索引之间检索列表的方法,但在本例中,最好使用slice:)

def GetCombilistBeween(从数字到数字):
combiList=[]
如果fromNumber0,则累积[pF-1],否则为0)
结束=t编号-1
对于范围内的p(pF,pT+1):
combiList+=[“”.join(项目)用于itertools.islice(itertools.product(alphaNumList,repeat=p+1)中的项目,开始,分钟(累积[p],结束)+1)]
开始=0
结束-=累计[p]
其他:
append(getCombiFromIndex(fromNumber))
返回战斗员
打印(getCombiListBetween(81898191))#['][',']]','aaa']

如果你有内存,你可以按索引将组合存储在字典中。但这会消耗大量内存,是的。相关:@Jean Françoisfare我知道,但我想不循环地使用它,我需要非常快地获取索引。有人会在itertools.islice(itertools.product)中为item编写类似“result=[”.join(item))这样的代码(alphaNumList,repeat=6),0,1)“几乎完美,但太快了,但想法就在这里哦,好的,谢谢,我以前用阶乘写过类似的东西。我明白你的意思,我认为工作太长了:/
def groups(n, r):
    return [comb(n-i-1, r-1) for i in range(n-r+1)]

>>> comb(8, 3)
56
>>> groups(8, 3)
[21, 15, 10, 6, 3, 1]
from itertools import combinations

population = 'ABCDEFGH'
for r in range(len(population) + 1):
    for i, expected in enumerate(combinations(population, r)):
        actual = locate(list(population), r, i)
        assert expected == actual
import itertools

alphaNumList = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&-()@=+;/!%$\\'\",.<>*^{}#~_[]")

cumulative = [len(alphaNumList)]
for i in range(1, 10):
    cumulative.append(len(alphaNumList) ** (i+1) + cumulative[i - 1])


def getCombiFromIndex(combiNumber):
    p = 0
    while cumulative[p] < combiNumber:
        p += 1  # WARNING : not robust to combi greater than (10,90) in my case :)
    rest = combiNumber - 1 - (cumulative[p - 1] if p > 0 else 0)
    return "".join([item for item in itertools.islice(itertools.product(alphaNumList, repeat=p + 1), rest, rest + 1)][0])


print(getCombiFromIndex(1))  # "a"
print(getCombiFromIndex(90))  # "]"
print(getCombiFromIndex(91))  # "aa"
print(getCombiFromIndex(800064))  # "ah+1"
def getCombiListBetween(fromNumber, toNumber):
    combiList = []
    if fromNumber < toNumber:
        pF, pT = 0, 0
        while cumulative[pF] < fromNumber:
            pF += 1
        while cumulative[pT] < toNumber:
            pT += 1
        start = fromNumber - 1 - (cumulative[pF - 1] if pF > 0 else 0)
        end = toNumber - 1
        for p in range(pF, pT + 1):
            combiList += ["".join(item) for item in itertools.islice(itertools.product(alphaNumList, repeat=p + 1), start, min(cumulative[p], end) + 1)]
            start = 0
            end -= cumulative[p]
    else:
        combiList.append(getCombiFromIndex(fromNumber))
    return combiList

print(getCombiListBetween(8189, 8191)) # ['][', ']]', 'aaa']