【问题标题】:How to remove item from a python list in a loop? [duplicate]如何在循环中从 python 列表中删除项目? [复制]
【发布时间】:2012-01-08 21:57:16
【问题描述】:

可能重复:
Remove items from a list while iterating in Python

我正在尝试从 python 的列表中删除一个项目:

x = ["ok", "jj", "uy", "poooo", "fren"]
for item in x:
    if len(item) != 2:
        print "length of %s is: %s" %(item, len(item))
        x.remove(item)

但它不会删除 "fren" 项目。有什么想法吗?

【问题讨论】:

    标签: python list


    【解决方案1】:

    您不能在迭代列表时从列表中删除项目。在旧列表的基础上构建新列表要容易得多:

    y = [s for s in x if len(s) == 2]
    

    【讨论】:

    • 好吧,吹毛求疵:你“可以”,但你会得到无用的结果,其他容器完全不允许它。
    • @delnan:好吧,如果您以相反的顺序遍历列表,那么您可以甚至获得有用的结果。但这可能并不比像 Sven 建议的那样创建一个新列表更快(而且肯定更令人困惑)。
    • 是的,我以相反的顺序执行,无需复制即可工作: x = len(system_list) # 删除范围内 i 的所有空条目(x-1, -1, -1): if not system_list [i]: 删除系统列表[i]
    • @radtek:由于从列表中删除项目是 O(n) 操作,因此该方法具有 O(n²) 最坏情况复杂度。
    • 这个答案非常有效。
    【解决方案2】:

    hymloth 和 sven 的答案有效,但他们不会修改列表(创建一个新列表)。如果您需要修改对象,则需要分配给切片:

    x[:] = [value for value in x if len(value)==2]
    

    但是,对于需要删除少量元素的大型列表,这会消耗内存,但它的运行时间为 O(n)。

    glglgl 的答案存在 O(n²) 复杂性,因为 list.remove 是 O(n)。

    根据您的数据结构,您可能更喜欢注意要删除的元素的索引,并使用del 键按索引删除:

    to_remove = [i for i, val in enumerate(x) if len(val)==2]
    for index in reversed(to_remove): # start at the end to avoid recomputing offsets
        del x[index]
    

    现在del x[i] 也是 O(n),因为您需要复制索引 i 之后的所有元素(列表是向量),因此您需要针对您的数据进行测试。这仍然应该比使用remove 更快,因为您不需要支付删除搜索步骤的成本,并且两种情况下的复制步骤成本是相同的。

    [编辑] 非常好的就地、O(n) 版本,内存要求有限,由@Sven Marnach 提供。它使用在 python 2.7 中引入的itertools.compress

    from itertools import compress
    
    selectors = (len(s) == 2 for s in x)
    for i, s in enumerate(compress(x, selectors)): # enumerate elements of length 2
        x[i] = s # move found element to beginning of the list, without resizing
    del x[i+1:]  # trim the end of the list
    

    【讨论】:

    • 这是一个原地 O(n) 版本,只需要 O(1) 额外内存:ideone.com/F10fB。它并不比您的 O(n^2) 版本更复杂。 (+1 以获得详细答案,顺便说一句)
    • 不错的一个。您应该将其作为答案发布在 SO 上。
    • 为什么要分配给x[:] 而不仅仅是x
    • 该代码并不真正适合我的答案,但它非常适合 your 答案中的讨论。关心整合它吗? (请注意,itertools.compress() 是在 Python 2.7 中引入的。)
    • @KirkStrauser:将语义更改为就地操作。另见stackoverflow.com/a/1208792/279627
    【解决方案3】:
    x = [i for i in x if len(i)==2]
    

    【讨论】:

      【解决方案4】:

      这源于这样一个事实,即在删除时,迭代会跳过一个元素,因为它似乎只对索引起作用。

      解决方法可能是:

      x = ["ok", "jj", "uy", "poooo", "fren"]
      for item in x[:]: # make a copy of x
          if len(item) != 2:
              print "length of %s is: %s" %(item, len(item))
              x.remove(item)
      

      【讨论】:

      • 嗯...你是对的。因此,就时间而言,hymloth 和您的解决方案似乎是最好的 AFAICT...
      【解决方案5】:

      已经提到的列表理解方法可能是您最好的选择。但是,如果您绝对想就地执行此操作(例如,如果 x 真的很大),这是一种方法:

      x = ["ok", "jj", "uy", "poooo", "fren"]
      index=0
      while index < len(x):
          if len(x[index]) != 2:
              print "length of %s is: %s" %(x[index], len(x[index]))
              del x[index]
              continue
          index+=1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-05
        • 2021-11-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-26
        相关资源
        最近更新 更多