为什么for循环只执行一次?

时间:2018-02-01 16:29:10

标签: python-3.x

我试图删除nums中的val值。

nums=[3,3]  
val=3

class Solution:
    def removeElement(self, nums, val):
        if not nums:
            return []
        for i in nums:
            if i == val:
                nums.remove(i)
        return nums

我除外:[]

但输出:[3]

也许这是一个愚蠢的问题。但我希望有人可以帮我解释一下。谢谢。

6 个答案:

答案 0 :(得分:1)

这是一个很好的例子,说明为什么在迭代它时不应该修改列表。列表有点不寻常,因为它实际上允许您以相当可预测的方式进行修改。如果你尝试的话,许多其他可迭代对象都会引发错误。

当您for i in nums时,它会转换为for i in iter(nums)。列表上的迭代器跟踪您所在的索引。以下是循环中发生的事情:

  1. nums[3, 3],迭代器位于零位置:

    3, 3
    ^
    
  2. 该项目与val匹配,因此会被删除。该列表被移回一个项目:

    3
    ^
    
  3. 迭代器向前移动一个项目。这是列表的结尾,因此迭代停止:

    3
      ^
    
  4. 只要您在列表中按顺序排列任何匹配元素对,就会发生这种情况。如果您的列表是[3, 4, 3]

    ,则不会发生这种情况
    1. 开始

      3, 4, 3
      ^
      
    2. 删除

      4, 3
      ^
      
    3. 增量

      4, 3
         ^
      
    4. 删除

      4
         ^
      
    5. 结束

    6. 有两种方法可以获取已过滤的列表。最明显的,就是在其他答案中被扼杀,通常是通过理解来制作一个新的清单:

      nums = [x for x in nums if x != val]
      

      然而,还有一个就地解决方案。这不是最佳选择,但对于必须工作的情况,这是可能的。如果您智能地迭代索引,则可以始终实现自己的迭代步骤:

      i = 0
      while i < len(nums):  # Note that len is called in every iteration
          if nums[i] == val:
              nums.remove[i]
          else:
              i += 1
      

      如果您的方法由于某种原因无法返回列表,那么这样的事情是个好主意。

      作为事后的想法,你甚至可以通过理解来进行就地过滤:

      nums[:] = [x for x in nums if x != val]
      

      这会创建一个临时列表,并将其内容分配给nums内容,但不会更改对象nums所指的对象

答案 1 :(得分:0)

迭代时不要删除(或更改)列表。

理解会解决你的问题:

nums = [i for i in nums if i != val]

您的案件发生了什么?

  1. 你经历了清单。
  2. 第一个元素是3
  3. 你删除了它。
  4. 第二个元素成为第一个元素。
  5. 您已经检查了第一个元素,现在它被跳过了。
  6. 循环结束。
  7. 您将离开[3]

答案 2 :(得分:0)

正如@tobias_k在评论中所说,在迭代该列表时从列表中删除项目是个坏主意。相反,您应该跟踪另一个不等于参数val的项目列表。

def removeElement(self, nums, val):
    if not nums:
        return []
    remaining = []
    for num in nums:
        if num != val:
            remaining.append(num)
    return remaining

出于您的目的,我上面的内容在逻辑上等同于其他答案。

答案 3 :(得分:0)

当您遍历列表时从列表中删除项会导致问题,因为您导致列表在循环尝试跟踪其位置的同时转换。

假设您有一份水果清单:Apple,Banana,Banana,Cherry,Date。假设您要删除香蕉。所以你编写代码来做到这一点:

for each fruit in Fruits
    if fruit is Banana
        remove fruit

这是一种可能的场景,取决于编程语言或库如何实现迭代:首先,代码指向元素0(假设从零开始索引),在此处找到Apple。 Apple与香蕉不匹配。所以代码移动到列表中的下一个项目,位置1:香蕉。香蕉与香蕉相配,香蕉被移除。

现在名单Fruits由Apple,Banana,Cherry,Date组成。第二个香蕉位于第一个香蕉的位置1。樱桃现在坐在第二个香蕉的位置,位置2;并且约会坐在Cherry所在的位置,在第3位。

由于代码已经已经在位置1进行了比较和删除,因此它不会再做另一个!它是时候增加,继续前进到位置2,它找到了Cherry。这意味着它跳过了第二个香蕉。当循环完成时,你仍然会在那里拥有第二个香蕉。名单将是Apple,Banana,Cherry,Date。

可能工作的方法,取决于数组的实现方式(包括它们是否是动态的,您可以从中删除元素而不会导致其他元素重新排序),就是创建一个数组从列表中的元素开始,然后依次通过索引从n-1到0迭代它们(假设从零开始的数组)。您必须以相反的顺序执行此操作,否则您将遇到与以前相同的问题。当您以相反的顺序进行迭代时,删除会导致您已经访问过的元素移位,但不会移动您尚未访问过的元素。

答案 4 :(得分:-1)

for i in nums:
    if i == val:
        nums.remove(i)

问题是您在更改列表时正在迭代列表。在不编辑原始列表的情况下更快速地执行此操作的方法是使用列表解析:

if not nums:
    return 0
return (x for x in nums if x != val)

答案 5 :(得分:-1)

我不在python中工作,但从我看到的,你试图从数组中删除1个元素。如果您知道该元素,为什么不尝试: - 不要循环 - 尝试从numns中删除1个元素 - 如果需要,使用异常处理,即元素可能不存在于数组中 - 返回nums

一旦找到元素,你也可以尝试退出循环。如果删除了要删除的元素,则无需进一步操作。

相关问题