<p>您正试图删除索引<code>2</code>处的项,但您已经删除了该项。在</p>
<p>Python索引从<em>0</em>开始,而不是1,因此<code>2</code>是<strong>第三个</strong>项。换句话说,列表<code>[1, 2]</code>的长度大于1(有2个项),但该列表中只存在索引<code>0</code>和{<cd5>}。在</p>
<p>您可以将打印添加到循环中以查看发生了什么:</p>
<pre><code>def josephus(items, k):
while len(items) > 1:
print(items)
del items[k]
return items
</code></pre>
<p>并使用略短的列表调用函数以保持输出的可管理性:</p>
^{pr2}$
<p>这表明您每次都在删除第3项,当只剩下2项时会抛出错误。在</p>
<p>您可以测试大于<code>k</code>的长度,而不是对长度进行硬编码:</p>
<pre><code>def josephus(items, k):
while len(items) > k:
del items[k]
return items
</code></pre>
<p>现在循环条件保证在索引<code>k</code>处有一个元素要删除:</p>
<pre><code>>>> def josephus(items, k):
... while len(items) > k:
... del items[k]
... return items
...
>>> josephus([1,2,3,4], 2)
[1, 2]
</code></pre>
<p>然而,从给定的索引中删除所有内容需要做大量的工作。只需使用一个<em>切片</em>:</p>
<pre><code>def josephus(items, k):
del items[k:]
return items
</code></pre>
<p><code>[k:]</code>符号告诉Python处理从索引<code>k</code>开始的所有项,直到列表的末尾(在<code>:</code>后面没有值)。在</p>
<p>但是,如果要删除第<code>k</code>个元素(所以每第二个或第三个元素,等等),那么您就走错了方向。再次使用切片表示法:</p>
<pre><code>del items[::k]
</code></pre>
<p>我填补了第三个缺口,那就是跨步。这将删除元素<code>0 + 0 * k</code>,和<code>0 + 1 * k</code>,和<code>0 + 2 * k</code>等:</p>
<pre><code>>>> items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> items[::2]
[1, 3, 5, 7, 9]
>>> del items[::2]
>>> items
[2, 4, 6, 8, 10]
</code></pre>
<p>如果您正在尝试实现<a href="http://en.wikipedia.org/wiki/Josephus_problem" rel="nofollow">Josephus problem</a>,则不能使用此方法删除项,因为删除必须是循环的,至少不计算下一轮清除的新起点。使用<code>%</code>模数运算符绕圆旋转,根据变化的长度进行调整:</p>
<pre><code>def josephus(items, k):
skip = k - 1 # deletion removes the item, so skip k - 1
index = skip % len(items)
while len(items) > 1:
del items[index]
index = (index + skip) % len(items)
return items[0]
</code></pre>
<p>注意,我现在返回的是一个幸存的项目,而不是列表。在</p>
<p>代码跟踪要在^{<cd16>中删除的<em>下一个</em>项。我们从<code>k - 1</code>开始调整基于0的索引;第二项位于<code>1</code>。然后,我们通过递增<code>k - 1</code>步来绕着这个“圆”,因为我们刚刚删除了第<code>k</code>项,之后的所有内容都将围绕着圆圈上移一步,并使用<code>%</code>返回到列表的开头。在</p>