Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
解释列出所有排列的Python代码_Python_Generator_Permutation - Fatal编程技术网

解释列出所有排列的Python代码

解释列出所有排列的Python代码,python,generator,permutation,Python,Generator,Permutation,联机找到此代码()。我试图弄明白,但没有取得多大进展。真正让我感到困惑的是: class Permutation: def __init__(self,justalist): self._data = justalist[:] self._sofar = [] def __iter__(self): return self.next() def next(self): for elem in self._da

联机找到此代码()。我试图弄明白,但没有取得多大进展。真正让我感到困惑的是:

class Permutation:
    def __init__(self,justalist):
        self._data = justalist[:]
        self._sofar = []
    def __iter__(self):
        return self.next()
    def next(self):
        for elem in self._data:
            if elem not in self._sofar:
                self._sofar.append(elem)
                if len(self._sofar) == len(self._data):
                    yield self._sofar[:]
                else:
                    for v in self.next():
                        yield v
                self._sofar.pop()
要运行类的代码,请执行以下操作:

                 for v in self.next():
                    yield v
                 self._sofar.pop()
我读过:

“通过调用yield,下一个成员现在是一个生成器函数,因此我们不能简单地再次调用next-如果这样做,我们将丢失返回的生成器对象,从而丢失返回的置换!我们必须在self中使用一个简单的for v循环返回的结果。next():yield v。这样,结果将正确地传播到”家长“呼叫”


我不知道这是否能解释发生了什么,但这对我来说毫无意义。(我以为我理解生成器。)

这个类是一个递归调用自身的生成器(
self.next()

这有点奇怪,因为当您要求生成器提供其所有值时,它并不像您所期望的那样返回
self
(一个带有
.next()
函数的对象),从而真正遵循迭代协议。相反,它返回self.next()的结果,这是非常糟糕的措辞。
next
函数应该被称为
permutations()
,因为
next
函数实际上与迭代协议中需要
next
函数这一事实无关

无论如何,如果使用递归深度参数扩充函数,则可以看到此函数的递归跟踪:

      for i in Permutation(a):
         print(i)
演示:

如您所见,数据流如下所示:递归前进到最深的级别(在本例中为4,
len([0,1,2,3])
is 4),生成置换,并返回到上一级别。该水平将使其返回到上一水平,以此类推。在最高水平,收益率将返回该水平

总之,这是一个失败而糟糕的实施,因为:

  • 它可以通过一个带有这个额外类的递归函数模式来完成
  • 它定义了
    next()
    ,在某种程度上强烈暗示了某些东西,但实际上却做了其他事情
  • 如果有任何值重复,它将失败,例如,
    置换([0,1,1])
    将失败

  • 您应该只使用(
    来自itertools导入置换)

    这个类是一个递归调用自身的生成器(
    self.next()

    这有点奇怪,因为当您要求生成器提供其所有值时,它并不像您所期望的那样返回
    self
    (一个带有
    .next()
    函数的对象),从而真正遵循迭代协议。相反,它返回self.next()
    的结果,这是非常糟糕的措辞。
    next
    函数应该被称为
    permutations()
    ,因为
    next
    函数实际上与迭代协议中需要
    next
    函数这一事实无关

    无论如何,如果使用递归深度参数扩充函数,则可以看到此函数的递归跟踪:

          for i in Permutation(a):
             print(i)
    
    演示:

    如您所见,数据流如下所示:递归前进到最深的级别(在本例中为4,
    len([0,1,2,3])
    is 4),生成置换,并返回到上一级别。该水平将使其返回到上一水平,以此类推。在最高水平,收益率将返回该水平

    总之,这是一个失败而糟糕的实施,因为:

  • 它可以通过一个带有这个额外类的递归函数模式来完成
  • 它定义了
    next()
    ,在某种程度上强烈暗示了某些东西,但实际上却做了其他事情
  • 如果有任何值重复,它将失败,例如,
    置换([0,1,1])
    将失败

  • 您应该只使用(
    从itertools导入排列

    关键思想是
    排列。next()
    生成
    \u数据
    中以
    \u开头的所有项目排列

    为此,我们尝试将每个可能的元素添加到
    \u sofar
    的末尾。然后有两种情况:要么
    \u sofar
    足够长(即,我们有一个完整的排列),在这种情况下,我们只产生一个副本;或者它不是(也就是说,我们有一个部分排列),在这种情况下,我们递归地调用
    next
    ——通常,这会产生很多排列,所以我们必须一个接一个地产生它们

    顺便说一句,如果代码更像这样,我认为代码会更整洁、更容易理解(危险:未经测试的代码):


    它还有一个优点,就是在没有元素的情况下给出正确的答案(只有一个排列,即空序列;给定的代码不会产生任何元素)。我也倾向于进行一些优化,但它们并不重要。

    关键思想是
    排列。next()
    产生
    \u data
    中所有以
    \u sofar
    开头的项的排列

    为此,我们尝试将每个可能的元素添加到
    \u sofar
    的末尾。然后有两种情况:要么
    \u sofar
    足够长(即,我们有一个完整的排列),在这种情况下,我们只产生一个副本;或者它不是(也就是说,我们有一个部分排列),在这种情况下,我们递归地调用
    next
    ——通常,这会产生很多排列,所以我们必须一个接一个地产生它们

    顺便说一句,如果代码更像这样,我认为代码会更整洁、更容易理解(危险:未经测试的代码):


    它还有一个优点,就是在没有元素的情况下给出正确的答案(只有一个排列,即空序列;给定的代码不会产生任何元素)。我也倾向于做一些优化,但它们并不重要。

    尝试一下
    产量
    ,编写一个生成器函数
    >>> list( Permutation(range(4)) )
                             yielding self._sofar[:]: [0, 1, 2, 3]
                     yielding elements of self.next() one-by-one: [0, 1, 2, 3]
             yielding elements of self.next() one-by-one: [0, 1, 2, 3]
     yielding elements of self.next() one-by-one: [0, 1, 2, 3]
                             yielding self._sofar[:]: [0, 1, 3, 2]
                     yielding elements of self.next() one-by-one: [0, 1, 3, 2]
             yielding elements of self.next() one-by-one: [0, 1, 3, 2]
     yielding elements of self.next() one-by-one: [0, 1, 3, 2]
                             yielding self._sofar[:]: [0, 2, 1, 3]
                     yielding elements of self.next() one-by-one: [0, 2, 1, 3]
             yielding elements of self.next() one-by-one: [0, 2, 1, 3]
     yielding elements of self.next() one-by-one: [0, 2, 1, 3]
                             yielding self._sofar[:]: [0, 2, 3, 1]
                     yielding elements of self.next() one-by-one: [0, 2, 3, 1]
             yielding elements of self.next() one-by-one: [0, 2, 3, 1]
     yielding elements of self.next() one-by-one: [0, 2, 3, 1]
                             yielding self._sofar[:]: [0, 3, 1, 2]
                     yielding elements of self.next() one-by-one: [0, 3, 1, 2]
             yielding elements of self.next() one-by-one: [0, 3, 1, 2]
     yielding elements of self.next() one-by-one: [0, 3, 1, 2]
                             yielding self._sofar[:]: [0, 3, 2, 1]
                     yielding elements of self.next() one-by-one: [0, 3, 2, 1]
             yielding elements of self.next() one-by-one: [0, 3, 2, 1]
     yielding elements of self.next() one-by-one: [0, 3, 2, 1]
                             yielding self._sofar[:]: [1, 0, 2, 3]
                     yielding elements of self.next() one-by-one: [1, 0, 2, 3]
             yielding elements of self.next() one-by-one: [1, 0, 2, 3]
     yielding elements of self.next() one-by-one: [1, 0, 2, 3]
    
    def next(self):
        if len(self._sofar) == len(self._data):
            yield self._sofar[:]
        else:
            for elem in self._data:
                if elem not in self._sofar:
                    self._sofar.append(elem)
                    for v in self.next():
                        yield v
                    self._sofar.pop()