我在CS61a遇到了一个problem:

给定一个唯一元素的序列,该序列的排列是以某种任意顺序包含该序列的元素的列表.例如,[2, 1, 3][1, 3, 2][3, 2, 1]是序列1, 2, 3]的一些排列.

实现gen_perms,这是一个生成器函数,它接受序列seq并返回一个生成器,该生成器产生seq的所有排列.对于这个问题,假设seq不是空的.

排列可以以任何顺序产生.

我的解决方案是:

def gen_perms(seq):
    def generator(seq_):
        list_seq=list(seq_)
        if len(list_seq)==1:
            yield list_seq
        else:
            for item in generator(list_seq[1:]):
                for i in range(len(list_seq)):
                    yield item[:i]+[list_seq[0]]+item[i:]
    return generator(seq)

呼叫示例:

print(list(gene_perms([1, 2, 3])))

以上代码输出预期结果:

[[1, 2, 3], [2, 1, 3], [2, 3, 1], [1, 3, 2], [3, 1, 2], [3, 2, 1]]

我的怀疑是,它看起来不应该有正确的输出.在我的代码中,generator是递归构建的,generator(list_seq[1:])yield行出现在generator(list_seq)行之前,它应该首先产生其子序列的置换,然后才是序列本身的置换.但前者甚至没有出现在输出中.

有人能解释一下吗?也许我对发电机的工作原理有错误的理解.

推荐答案

虽然yield个更深的递归调用发生在earlier处,但这些产生的值是for循环的consumed个,该for循环进行了那个更深的递归调用.这些产生的值不会神奇地在整个递归树上冒泡!它们由直接调用方使用,而不是由递归堆栈较高层的任何调用方使用.

每个生成器执行都(唯一)负责将值提供给它们的直接使用者.递归中更深的调用不会生成顶级调用方将看到的值.

关于您的代码的其他注释

与您的问题无关,但是:

  • 如果您的代码将获得一个空列表作为输入,则它将进入无限递归.为了避免这种情况,请将其作为递归的基本情况.

  • 您不应该在代码中显式地生成lists;不要创建包含list(seq_)[seq[0]]的列表,因为:

    • 如果输入序列是一个字符串,您不希望生成作为其排列的列表,而是字符串.取而代之的是,在你的yield中,取一片来注入第一个元素,所以不是[seq[0]](这会创建一个列表),而是seq[:1]:这对字符串和元组也很有效.
    • 序列支持您对其执行的所有操作(值得注意的是,slicing)
    • 如果您担心原始输入的Mutations :您的代码mutates中没有任何生成的排列.此外,如果顶级调用者如此不明智地改变他们从该过程中获得的列表,这不会对该过程产生负面影响.原因是您在循环中执行的yield已经创建了一个新序列(通过使用切片和+操作符).
  • 因为您的内部函数与外部函数具有相同的签名(参数和返回类型),所以您不需要内部函数:只需递归调用gen_perms即可.

考虑到这些因素,您的职能可能是:

def gen_perms(seq):
    if not seq:
        yield seq
    else:
        for item in gen_perms(seq[1:]):
            for i in range(len(seq)):
                yield item[:i] + seq[:1] + item[i:]

示例运行

print(*gen_perms([1,2,3]))  # list input
# -> [1, 2, 3] [2, 1, 3] [2, 3, 1] [1, 3, 2] [3, 1, 2] [3, 2, 1]
print(*gen_perms((1,2,3)))  # tuple input
# -> (1, 2, 3) (2, 1, 3) (2, 3, 1) (1, 3, 2) (3, 1, 2) (3, 2, 1)
print(*gen_perms("abc"))    # string input
# -> abc bac bca acb cab cba

(诚然,输入不应该是range实例,因为输出不能有"排列"的范围;不存在这种情况.我假设代码质询并不打算使用Range对象调用此函数)

Python相关问答推荐

当使用keras.utils.Image_dataset_from_directory仅加载测试数据集时,结果不同

比较2 PD.数组的令人惊讶的结果

PywinAuto在Windows 11上引发了Memory错误,但在Windows 10上未引发

如何在类和classy-fastapi -fastapi- followup中使用FastAPI创建路由

如何过滤包含2个指定子字符串的收件箱列名?

无法定位元素错误404

有没有一种方法可以从python的pussompy比较结果中提取文本?

将JSON对象转换为Dataframe

未知依赖项pin—1阻止conda安装""

为什么Django管理页面和我的页面的其他CSS文件和图片都找不到?'

剪切间隔以添加特定日期

30个非DATETIME天内的累计金额

判断Python操作:如何从字面上得到所有decorator ?

504未连接IB API TWS错误—即使API连接显示已接受''

PYTHON中的pd.wide_to_long比较慢

文本溢出了Kivy的视区

通过对列的其余部分进行采样,在Polars DataFrame中填充_null`?

使用pythonminidom过滤XML文件

如何通过特定导入在类中执行Python代码

Fake pathlib.使用pyfakefs的类变量中的路径'