小能豆

从多个迭代器的任意状态进行迭代,其中: i1 < i2 < i3 ... < in

Python

我正在循环使用多个迭代器,每个迭代器都可以取 0 到 193 之间的值,并且每个迭代器还必须大于前一个迭代器 (i1 < i2 < i3 … < in)。

对于这个例子,我有 5 个迭代器;要迭代的状态总数非常大 (2,174,032,288)。因此,我正在分批处理这些状态并保存每批的开始和最终“状态”,这样我就可以从它停止的地方继续。

我的以下代码有效。我的问题是什么是概括这些嵌套 if 语句的最佳方法,以便它适用于任意数量的有序迭代器,而不仅仅是 5 个。此外,是否有更好的方法来实现这一点?

rnIndex = [0, 1, 2, 3, 4]  # the starting state of indices to iterate from
batchSize = 1000000  # iterate through 1 million index states per batch
batchNumber = 0  # the batch number to start from - 1
batchNumberMax = 10  # run up to and including this batch number
rnLimit = 194  # iterate up to (but not including) for each index
rnComplete = False

while not rnComplete and batchNumber < batchNumberMax:
    batchNumber += 1
    print('\nStart index (included): ' + str(rnIndex))
    rnBatch = []
    for i in range(batchSize):
        if i == batchSize - 1:
            print('Final index (included): ' + str(rnIndex))
        rnBatch.append(rnIndex)  # add each rnIndex to rnBatch
        rnIndex[-1] += 1
        if rnIndex[-1] == rnLimit:
            rnIndex[-2] += 1
            rnIndex[-1] = rnIndex[-2] + 1
            if rnIndex[-2] == rnLimit - 1:
                rnIndex[-3] += 1
                rnIndex[-2] = rnIndex[-3] + 1
                rnIndex[-1] = rnIndex[-2] + 1
                if rnIndex[-3] == rnLimit - 2:
                    rnIndex[-4] += 1
                    rnIndex[-3] = rnIndex[-4] + 1
                    rnIndex[-2] = rnIndex[-3] + 1
                    rnIndex[-1] = rnIndex[-2] + 1
                    if rnIndex[-4] == rnLimit - 3:
                        rnIndex[-5] += 1
                        rnIndex[-4] = rnIndex[-5] + 1
                        rnIndex[-3] = rnIndex[-4] + 1
                        rnIndex[-2] = rnIndex[-3] + 1
                        rnIndex[-1] = rnIndex[-2] + 1
                        if rnIndex[-5] == rnLimit - 4:
                            rnComplete = True
                            break
    print('len(rnBatch) = '+str(len(rnBatch)))  # check the length of rnBatch

print(rnIndex)  # the rnIndex state to resume from

出去:

Start index (included): [0, 1, 2, 3, 4]
Final index (included): [0, 1, 94, 99, 133]
len(rnBatch) = 1000000

...

Start index (included): [0, 8, 24, 122, 173]
Final index (included): [0, 9, 23, 54, 90]
len(rnBatch) = 1000000

Start index (included): [0, 9, 23, 54, 91]
Final index (included): [0, 10, 22, 182, 188]
len(rnBatch) = 1000000
[0, 10, 22, 182, 189]

Process finished with exit code 0

阅读 94

收藏
2023-05-29

共1个答案

小能豆

您可以编写一个函数,根据前一个索引生成下一个索引序列,并使用它从任何起点推进组合:

def nextSeq(maxVal,values):
    for i,v in enumerate(reversed(values),1):
        if v <= maxVal-i:
            return values[:-i]+[values[-i]+k+1 for k in range(i)]

输出:

seq = [0,1,2,3,4]
for _ in range(10):
    print(seq)
    seq = nextSeq(193,seq)

[0, 1, 2, 3, 4]
[0, 1, 2, 3, 5]
[0, 1, 2, 3, 6]
[0, 1, 2, 3, 7]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 9]
[0, 1, 2, 3, 10]
[0, 1, 2, 3, 11]
[0, 1, 2, 3, 12]
[0, 1, 2, 3, 13]

该函数还可用于创建可在 for 循环(无嵌套)中使用的生成器:

def genSeq(maxVal,start):
    seq = list(start)
    while seq:
        yield seq
        seq = nextSeq(maxVal,seq)

输出:

start = [188,189,190,191,192]
for seq in genSeq(193,start):
    print(seq)

[188, 189, 190, 191, 192]
[188, 189, 190, 191, 193]
[188, 189, 190, 192, 193]
[188, 189, 191, 192, 193]
[188, 190, 191, 192, 193]
[189, 190, 191, 192, 193]

如果你想直接跳转到特定的序列(第N个序列),递归函数可以将索引转换为顺序相同的序列:

from math import factorial as fact
def seqAtIndex(index,maxVal,size):
    if size == 1: return [index]
    value  = base = chunk = 0
    while base+chunk <= index:
        base  += chunk
        value += 1
        chunk  = fact(maxVal+1-value)//fact(size-1)//fact(maxVal+2-value-size)
    return [value-1] \
         + [value+s for s in seqAtIndex(index-base,maxVal-value,size-1)]

输出:

for i in range(10): 
    print(i,seqAtIndex(i,193,5))

0 [0, 1, 2, 3, 4]
1 [0, 1, 2, 3, 5]
2 [0, 1, 2, 3, 6]
3 [0, 1, 2, 3, 7]
4 [0, 1, 2, 3, 8]
5 [0, 1, 2, 3, 9]
6 [0, 1, 2, 3, 10]
7 [0, 1, 2, 3, 11]
8 [0, 1, 2, 3, 12]
9 [0, 1, 2, 3, 13]

for i in range(2174032280,2174032288):
    print(i,seqAtIndex(i,193,5))

2174032280 [187, 189, 191, 192, 193]
2174032281 [187, 190, 191, 192, 193]
2174032282 [188, 189, 190, 191, 192]
2174032283 [188, 189, 190, 191, 193]
2174032284 [188, 189, 190, 192, 193]
2174032285 [188, 189, 191, 192, 193]
2174032286 [188, 190, 191, 192, 193]
2174032287 [189, 190, 191, 192, 193]

请注意,它比orseqAtIndex慢得多,所以您应该只使用它来查找起始序列,然后使用其他函数按顺序前进nextSeq``genSeq

2023-05-29