<p>您在注释中提到代码<a href="http://docs.python.org/2/library/itertools.html#itertools.combinations" rel="nofollow">here</a>对您是不透明的。但这可能是实现您所要实现的<code>combinations</code>函数的最佳方法,而且它值得理解,所以我将尝试详细解释它。在</p>
<p>其基本思想是,给定一个序列和多个可供选择的项,我们可以将每个组合表示为给定序列中的一系列索引。例如,假设我们有一个列表<code>['a', 'b', 'c', 'd', 'e']</code>,我们希望从该列表生成两个值的所有组合。在</p>
<p>我们的第一个组合是这样的。。。在</p>
<pre><code>['a', 'b', 'c', 'd', 'e']
^ ^
</code></pre>
<p>…并由索引列表<code>[0, 1]</code>表示。我们的下一个组合如下:</p>
^{pr2}$
<p>并由索引列表<code>[0, 2]</code>表示。在</p>
<p>我们继续向前移动第二个插入符号,将第一个插入符号保持在适当的位置,直到第二个插入符号到达末尾。然后我们将第一个插入符号移动到索引<code>1</code>,并通过将第二个插入符号移回索引<code>2</code>来“重置”进程。在</p>
<pre><code>['a', 'b', 'c', 'd', 'e']
^ ^
</code></pre>
<p>然后我们重复这个过程,向前移动第二个插入符号直到它到达结尾,然后将第一个向前移动一个并重置第二个。在</p>
<p>现在我们必须通过操纵索引列表来找出如何做到这一点。事实证明这很简单。最终组合如下:</p>
<pre><code>['a', 'b', 'c', 'd', 'e']
^ ^
</code></pre>
<p>它的索引表示是<code>[3, 4]</code>。这些是索引的最大可能值,并且等于<code>i + n - r</code>,其中<code>i</code>是列表中的位置,<code>n</code>是值的数目(在本例中是<code>5</code>),而{<cd12>}是选择数(在本例中是<code>2</code>)。因此,一旦某个特定的指数达到这个值,它就不能再高了,而且需要“重置”。在</p>
<p>考虑到这一点,下面是对代码的一步一步的分析:</p>
<pre><code>def combinations(iterable, r):
pool = tuple(iterable)
n = len(pool)
</code></pre>
<p>首先,给定基于上述示例的输入,<code>pool</code>将是我们上面转换成元组的字符列表,<code>n</code>只是池中的项数。在</p>
<pre><code>if r > n:
return
</code></pre>
<p>在没有替换的情况下,我们不能从<code>n</code>项列表中选择超过<code>n</code>个项目,因此在这种情况下我们只返回。在</p>
<pre><code>indices = range(r)
</code></pre>
<p>现在我们有了索引,初始化为第一个组合(<code>[0, 1]</code>)。所以我们放弃它:</p>
<pre><code>yield tuple(pool[i] for i in indices)
</code></pre>
<p>然后我们使用无限循环生成剩余的组合。在</p>
<pre><code>while True:
</code></pre>
<p>在循环中,我们首先向后遍历索引列表,搜索尚未达到最大值的索引。我们使用上面描述的公式(<code>i + n - r</code>)来确定给定索引的最大值。如果我们发现一个索引没有达到它的最大值,那么我们就跳出循环。在</p>
<pre><code> for i in reversed(range(r)):
if indices[i] != i + n - r:
break
</code></pre>
<p>如果我们找不到一个,那就意味着所有的索引都达到了它们的最大值,所以我们就完成了迭代。(这使用鲜为人知的<code>for-else</code>构造;只有当<code>for</code>循环正常终止时,<code>else</code>块才会执行。)</p>
<pre><code> else:
return
</code></pre>
<p>现在我们知道索引<code>i</code>需要递增:</p>
<pre><code> indices[i] += 1
</code></pre>
<p>另外,<code>i</code>之后的索引都处于最大值,因此需要重置。在</p>
<pre><code> for j in range(i+1, r):
indices[j] = indices[j-1] + 1
</code></pre>
<p>现在我们有了下一组指数,所以我们得出另一个组合。在</p>
<pre><code> yield tuple(pool[i] for i in indices)
</code></pre>
<p>这种方法有几种变体;在另一种方法中,不是向后遍历索引,而是向前一步,递增第一个索引,该索引与下一个索引之间存在“差距”,然后重置较低的索引。在</p>
<p>最后,您可以递归地定义它,尽管从实用的角度来看,递归定义可能没有那么有效。在</p>