Python-获取组合的索引
例如,我需要生成从“a”到“]]]]]的组合,为了实现这一点,我使用了这个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
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']