You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非嵌套实现多索引无重复全遍历的公式及迭代逻辑排查

问题描述

需求参考如下三层嵌套循环的遍历逻辑:

for i in range(3):
    for j in range(3):
        for k in range(3):
            print("{}{}{}".format(letter, number, symbol))

要求不使用嵌套for循环,仅通过操作i、j、k索引值、以数值计算方式生成完整遍历序列,实现可覆盖所有索引排列组合、适配不同长度索引集合的通用逻辑:需要实现.tick()方法,每次调用返回序列下一个元素,全程无重复输出。

现有实现的问题

目前已尝试基于类进位计数算法编写自定义Tick类,代码如下:

class Tick:
  def __init__(self, collections, func):
    self.collections = collections
    self.indexes = []
    self.loops = 0
    self.reset = -1
    self.func = func
    self.started = False
    for collection in collections:
      self.indexes.append(0)

  def size(self):
    total = len(self.collections[0])
    for collection in self.collections[1:]:
      total = total * len(collection)
    return total


  def tick(self):
    if self.started:
      if self.reset != -1:
         self.indexes[self.reset + 1] = 0
         for index in range(self.reset + 1, len(self.indexes)):
           
           self.indexes[index] = 0
         self.reset = -1
       
      else:
       self.loop = len(self.indexes) - 1
       while self.loop != -1 and self.indexes[self.loop] == len(self.collections[self.loop]) - 1:
         self.loop = self.loop - 1

       if self.loop == -1:
         return
       
       self.indexes[self.loop] = self.indexes[self.loop] + 1
       if self.loop < len(self.indexes) - 1:
         self.reset = self.loop
    else:
      self.started = True

    items = []
    for loop in range(len(self.indexes)):
      items.append(self.collections[loop][self.indexes[loop]])
    return self.func(items)
  
a = ["0", "1", "2"]      
b  = ["0", "1", "2"]
c = ["0", "1", "2"]

def printer(items):
  output = ""
  for item in items:
    output += item
  return output

ticker = Tick([a, b, c], printer)
print(ticker.size())
for index in range(ticker.size()):
  print(ticker.tick())

运行后出现重复输出,结果如下:

27
000
001
002
012
010
011
012
022
020
021
022
122
100
101
102
112
110
111
112
122
120
121
122
222
200
201
202

经重复行统计,012、022、112、122等值多次出现,27次总输出仅包含22个不同值,需要排查算法逻辑错误,给出正确实现。重复值统计结果:

COUNT    | LINE
-----------------------------------------------------
       3 |     122
       2 |     012
       2 |     022
       2 |     112
       1 |     000
       1 |     001
       1 |     002
       1 |     010
       1 |     011
       1 |     020
       1 |     021
       1 |     100
       1 |     101
       1 |     102
       1 |     110
       1 |     111
       1 |     120
       1 |     121
       1 |     200
       1 |     201
       1 |     202
       1 |     222
-----------------------------------------------------
      27 | TOTAL LINES
      22 | DISTINCT LINES
问题原因

原代码的进位重置逻辑存在时序错误:

  1. 某一位完成进位后,没有在同一次tick流程中把所有低位索引重置为0,而是把重置逻辑延后到下一次tick执行,导致进位当次的返回结果保留了低位的旧值,出现重复。
  2. 多余的started、reset状态变量增加了逻辑分支,很容易触发状态不一致的问题。
正确实现方案

直接用可变进制计数器的标准逻辑即可,不需要额外状态标记:

  • 初始化时所有索引位置为0,对应第一个组合
  • 每次调用tick时,先返回当前索引对应的组合值,再从最右侧(最低位)开始计算进位,为下一次返回做准备
  • 如果当前位加1后超过对应集合的最大索引,就把当前位置0,向左移动一位继续进位
  • 如果所有位都遍历完成(移动到索引-1的位置),标记遍历结束,后续调用返回None即可

修正后的代码:

class Tick:
    def __init__(self, collections, func):
        self.collections = collections
        # 存储每一位的当前索引,初始全0对应第一个组合
        self.indexes = [0] * len(collections)
        self.func = func
        # 标记是否已经遍历完所有组合
        self.exhausted = False

    def size(self):
        total = 1
        for collection in self.collections:
            total *= len(collection)
        return total

    def tick(self):
        if self.exhausted:
            return None
        
        # 先返回当前索引对应的组合(第一次调用直接返回全0的初始组合)
        items = [col[idx] for col, idx in zip(self.collections, self.indexes)]
        res = self.func(items)

        # 从最低位(最右侧)开始进位计算,为下一次tick做准备
        carry_pos = len(self.indexes) - 1
        while carry_pos >= 0:
            self.indexes[carry_pos] += 1
            # 当前位没到最大值,进位结束
            if self.indexes[carry_pos] < len(self.collections[carry_pos]):
                break
            # 当前位到最大值,归零,往左进位
            self.indexes[carry_pos] = 0
            carry_pos -= 1
        # 所有位都进位完了,标记遍历结束
        else:
            self.exhausted = True
        
        return res


# 测试
a = ["0", "1", "2"]      
b = ["0", "1", "2"]
c = ["0", "1", "2"]

def printer(items):
    return "".join(items)

ticker = Tick([a, b, c], printer)
print(ticker.size())
outputs = []
while True:
    val = ticker.tick()
    if val is None:
        break
    outputs.append(val)
    print(val)

# 验证无重复
print(f"总输出数:{len(outputs)}, 去重后数量:{len(set(outputs))}")

运行后会按顺序输出000到222的全部27种组合,无重复、无遗漏,同时支持不同长度的输入集合,比如传入长度分别为2、3、4的三个集合,也能正确遍历全部234=24种组合。

内容的提问来源于stack exchange,提问作者Samuel Squire

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 14:18:22