我这里有一个简单的程序,可以使用reversed()
返回的迭代器删除列表中的元素。
代码如下:
def removeElement( nums, val ):
for x in reversed(nums):
if x == val:
nums.remove(x)
如果我要使用for x in nums:
遍历列表,那么当一个元素(也是当前元素)被删除时,我们最终将跳过数组中的元素。但是,在使用reversed()
返回的迭代器的情况下不会发生这种情况,对remove()
的调用似乎对反向列表没有影响。
我还注意到两个列表中的每个元素都具有相同的内存地址,因此reversed()
不会分配一个全新的列表。
尽管调用reversed()
会影响原始列表,但remove()
返回的迭代器如何保留列表的原始结构?
答案 0 :(得分:4)
迭代器是否在Python中保留自己的数组副本?
否,或者至少在CPython中不是。我们可以对列表进行简单的测试:
>>> l = [1,2]
>>> for x in reversed(l):
... l[0] = 3
... print(x)
...
2
3
在这里,我们看到我们的编辑(l[0] = 3
)对产生什么元素有影响。最后,我们看到3
。如果reversed(..)
首先构造了一个副本,则它将发出1
。对于只有一个元素的列表,这是行不通的,因为在这种情况下,我们将x
设置为1
之前进入循环的正文,然后更改列表,将对该元素没有影响。
一个列表定义了一个__reversed__
函数,这意味着在进行reversed(..)
调用的情况下,它将使用此函数枚举相反的元素。可以在Python中实现此功能,例如:
class list:
# ...
def __reversed__(self):
for i in range(len(self)-1, -1, -1):
if i >= len(self):
yield self[i]
else:
break
在CPython中,它实际上是通过listreviterobject
object实现的,还具有一个索引decremented when accessing the next item的索引it_index
。我更新了Python版本,使其与CPython实现更加等效。
如果.remove()
元素,则将删除Python找到的第一项,因此它可能会“移动”光标下的元素。结果,有可能我们多次计数同一项目。然而,这最终不会产生太大影响。例如:
1 4 4 2 4 4
如果我们删除4
,我们将通过以下方式进行操作:
1 4 4 2 4 4 (start cursor at the right)
^
1 4 4 2 4 4 (start cursor at the right)
^
1 4 2 4 4 (remove 4)
^
1 4 2 4 4 (advance cursor)
^
1 2 4 4 (remove 4)
^
1 2 4 4 (advance cursor)
^
1 2 4 (remove 4)
^
1 2 4 (advance cursor)
^
1 2 (remove 4)
^
1 2 (advance cursor)
^
1 2 (advance cursor)
^
因此,鉴于光标位于我们要删除的元素上,我们将删除该元素的第一个匹配项。该位置始终位于左侧(或光标下方),因为如果光标位于该位置的左侧,则不能将其放置在该元素上。
如果删除了该元素,则可以说列表的一部分在“光标下方”移动。这意味着,由于光标向左移动,因此它相对地停留在同一位置。这将一直发生,直到删除最后一个元素。接下来,光标可以继续向左移动,并且永远不会再看到可以删除的元素(因为这些元素已经被删除)。
一个简单的程序可以产生经验证明其有效,如下所示:
while True:
l = [randint(0, 9) for _ in range(10)]
x = randint(0, 9)
removeElement(l, x)
assert x not in l
因此,我们在此处生成10个随机元素的列表,然后删除。最后,我们检查l
不再包含x
元素。当然,这不是 的基本证明,但如果运行了足够长的时间,它至少可以为我们提供一些证据,表明它适用于值在0
之间的10个元素的列表。和9
。
但是,最好不要同时以任何方式修改和迭代集合。如果您以后想要更改代码以查找当前元素和下一个元素,则可能会出错。
答案 1 :(得分:1)
reversed()
的官方文档说:
反向(seq)
返回一个反向迭代器。 seq必须是具有 reverse ()方法或支持序列协议( len ()方法和 getitem ()方法)的对象。整数参数从0开始)。
文档中似乎对该功能的工作方式没有任何进一步的保证。
给出该文档,我希望将reversed()
植入到A=("a", "b", "c", "d)
这样的列表中会返回A[3]
,A[2]
,A[1]
,最后是{{ 1}},我看不出给定实现会存储列表结构的原因。