python中的异常字符串列表行为

时间:2013-04-17 23:19:25

标签: python string list startswith

    print difflist
    for line in difflist:
        if ((line.startswith('<'))or (line.startswith('>')) or (line.startswith('---'))):
            difflist.remove(line)
    print difflist

这里,最初,

difflist = ['1a2', '> ', '3c4,5', '< staring', '---', '> starring', '> ', '5c7', '< at ', '---', '> add ', '']

我对代码的期望是打印

['1a2', '3c4,5', '5c7', '']

但我得到的是

difflist= ['1a2', '3c4,5', '---', '> ', '5c7', '---', '']

6 个答案:

答案 0 :(得分:3)

当迭代列表时,python保留它指向的数组元素的整数索引。但是,当您删除当前元素时,所有后面的元素都会转移到较低的索引。然后位置索引会增加,然后才能“看到”移动的元素取代您删除的元素。

最终,使用列表理解可以做得更好:

difflist = [ line for line in difflist if not line.startswith(('<','>','---'))]

如果您确实需要进行操作,只需在左侧使用切片分配:

difflist[:] = [ line for line in difflist if not line.startswith(('<','>','---'))]

答案 1 :(得分:2)

我认为你可能会使你的迭代器失效;换句话说,您不应该尝试删除正在循环的列表中的项目。

您可能想要制作一个新列表,其中只包含您关注的项目。

例如:

newdifflist = []
for line in difflist:
    if not ((line.startswith('<'))or (line.startswith('>')) or (line.startswith('---'))):
        newdifflist.append(line)

更多pythonic,使用列表推导和startswith()的多个参数:

newdifflist = [line for line in difflist if not line.startswith(('<', '>', '---')) ]

答案 2 :(得分:1)

result = []
for line in difflist:
    if not line.startswith(('<', '>', '---')):
        result += [line]

或使用列表推导:

[line for line in difflist if not line.startswith(('<', '>', '---'))]

答案 3 :(得分:1)

请改为:

>>> difflist = [i for i in difflist if not i.startswith(('<','>','---'))]
>>> difflist
['1a2', '3c4,5', '5c7', '']

执行.remove()更改顺序,因此(有点)会弄乱for循环。查看mgilson的答案以获取更多信息

答案 4 :(得分:0)

而不是尝试从列表中删除该项目,让它不做任何事情,并创建另一个列表与您想要的。

array = []
for line in difflist:
    if ((line.startswith('<'))or (line.startswith('>')) or (line.startswith('---'))):
        pass
    else:
        array.append(line)

现在数组将是您正在寻找的数组!

答案 5 :(得分:0)

对于正在发生的事情,没有任何“异常”。事实上这很正常。这是正在发生的事情:

  1. 循环正在查看项目 i
  2. i 符合您的测试,因此您将其删除。项目 i + 1 的内容现在是项目 i
  3. 您的循环再次开始,迭代器前进到指向项 i + 1 ,但 new 项目 i 从未进行过测试。< / LI>

    有几种可能的解决方案:

    1. 创建一个仅包含所需项目的新列表,而不是从现有列表中删除项目。这具有更好的算法复杂性,并且在Python中也更有效,但它可以使用更多内存。
    2. 以相反的顺序迭代列表。这样,你只会移动你已经看过的物品。
    3. 迭代一份清单。
    4. 使用内部while循环而不是if
    5. 对于这个问题,解决方案#4可能如下所示:

      for i, line in enumerate(difflist):
          while line.startswith(('<', '>', '---')):
              difflist.pop(i)
              line = difflist[i]
      

      这样,在测试失败之前,你一直在查看相同的索引,然后才允许迭代器继续下一个索引。

      (我冒昧地删除了你的条件中过多的不必要的括号,以及将remove改为pop - remove需要从头开始搜索每次列出,使你的循环成为Schlemiel the Painter's algorithm

      您可以考虑的另一件事是使用deque(来自collections模块);这是一个链表(常规Python list实际上是一个可调整大小的数组),从中删除元素会更快一些。