代码之家  ›  专栏  ›  技术社区  ›  chryss

停止递归生成器和排列

  •  3
  • chryss  · 技术社区  · 14 年前

    作为练习,我一直在尝试各种方法来生成Python中列表的所有排列——递归、非递归……--并将性能与 itertools.permutations() . 但是我在递归方法的生成器版本上遇到了问题,它不能用 StopIteration 异常,但却抛出 IndexError :

    def spawnperms(alist):
        """same algorithm as recursive option, but a generator"""
        if (alist == []):
            yield []
        for perm in spawnperms(alist[:-1]):
            for i in range(len(perm)+1):
                yield perm[:i] + [alist[-1]] + perm[i:]
    

    从python解释器调用:

    >>> for i in spawnperms(range(3)):
    ...     print i
    ... 
    [2, 1, 0]
    [1, 2, 0]
    [1, 0, 2]
    [2, 0, 1]
    [0, 2, 1]
    [0, 1, 2]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 5, in spawnperms
      File "<stdin>", line 5, in spawnperms
      File "<stdin>", line 5, in spawnperms
      File "<stdin>", line 7, in spawnperms
    IndexError: list index out of range
    

    哎哟。我试着用 pdb 它几乎在我的大脑中创建了一个堆栈溢出,但我理解的是递归“向下”到达空列表,然后到达外部(我想) for 循环耗尽了索引。

    如何更正我的代码?

    编辑: 从马克·拜尔斯那看似简单的正确答案中,我们可以学到: 干净的编码实践可以防止错误 . 如果我用过 else 之后系统地 if 不管我是否认为这种情况会被重新审视,这都不会发生。感觉还是很愚蠢!

    1 回复  |  直到 14 年前
        1
  •  6
  •   Mark Byers    14 年前

    你错过了一个 else :

    if (alist == []):
        yield []
    else:
        for ...
    

    这是因为 yield 行为方式与 return . 在 产量 当您请求下一个值时的语句。