【问题标题】:Generating permutations using generators使用生成器生成排列
【发布时间】:2019-10-22 14:17:25
【问题描述】:

我正在编写一个程序来生成字符串的所有排列:

def print_permutations_wrapper(str):
    strList = str.split()
    print_permutations(strList, 0, len(strList))


def print_permutations(strList: list, start: int, end: int):
    if start >= end - 1:
        print(strList)
        return

    print_permutations(strList, start+1, end)
    for i in range(start+1, end):
        strList[start], strList[i] = strList[i], strList[start]
        print_permutations(strList, start+1, end)
        strList[i], strList[start] = strList[start], strList[i]


def main():
    str = 'a b c'
    print_permutations_wrapper(str)


if __name__ == "__main__":
    main()

它工作正常,但不是打印它,我想使用yield懒惰地返回它:

def print_permutations_wrapper(str):
    strList = str.split()
    yield from print_permutations(strList, 0, len(strList))


def print_permutations(strList: list, start: int, end: int):
    if start >= end - 1:
        yield strList
        return

    yield from print_permutations(strList, start+1, end)
    for i in range(start+1, end):
        strList[start], strList[i] = strList[i], strList[start]
        yield from print_permutations(strList, start+1, end)
        strList[i], strList[start] = strList[start], strList[i]


def main():
    str = 'a b c'
    x = print_permutations_wrapper(str)
    print(list(x))

if __name__ == "__main__":
    main()

我得到的输出是:

[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]

而不是所有的排列。
如何纠正这个?

我正在使用 Python 3.7。

【问题讨论】:

  • 您正在变异相同的strList,因此结果将是相同列表的列表。您可以尝试在print_permutations 中使用yield list(strList) 来创建该列表的浅表副本,或者使用内置的itertools.permutations,文档包括示例实现。另见相关“Least Astonishment” and the Mutable Default Argument
  • @metatoaster yield list(strList) 生成该列表的深层副本,而不是浅层副本。
  • 哦,它现在可以工作了.. 谢谢!您可能想将其写在答案中。有趣的链接。对于初学者来说绝对是惊人的!
  • @AlbinPaul list 不会递归地复制可能是从参数接收到的引用列表中的任何内部引用。它只涉及顶级元素 - 您需要 deepcopy 来获得您的建议。

标签: python iterator generator permutation yield


【解决方案1】:

使用您的第二个程序,但添加print(strList) 将表明生成器函数产生了您所期望的结果,但最终输出显然不是您所期望的。这是因为结构化程序采用一个列表,但对同一副本执行所有操作(假设限制内存使用)。您也可以通过

验证这一点
>>> strList = ['a', 'b', 'c'] 
>>> items = list(print_permutations(strList, 0, 3))
>>> items[0] is items[1]
True
>>> items[0] is strList
True

很明显,items 中的每个项目都与传入的原始 strList 相同。鉴于问题的简单性,可以通过生成列表的浅表副本来避免这种情况。因此函数的相关yield部分将变为

def print_permutations(strList: list, start: int, end: int):
    if start >= end - 1:
        yield list(strList)
        return

现在运行它应该会产生:

>>> strList = ['a', 'b', 'c'] 
>>> items = list(print_permutations(strList, 0, 3))
>>> items[0] is items[1]
False

另外,顺便说一句,排列实际上是标准库的一部分,可通过itertools.permutation 获得。

相关:"Least Astonishment" and the Mutable Default Argument

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-18
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-05
    • 1970-01-01
    相关资源
    最近更新 更多