如果列表中的项目存在,如何删除它?

时间:2011-02-06 20:34:51

标签: python list

我从带有new_tagself.response.get("new_tag")的表单文本字段中获取selected_tags来自复选框字段

self.response.get_all("selected_tags")

我把它们组合成这样:

tag_string = new_tag
new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)

f1.striplist是一个删除列表中字符串内部空格的函数。)

但如果tag_list为空(未输入新标记)但有一些selected_tags,则new_tag_list包含空字符串" "

例如,来自logging.info

new_tag
selected_tags[u'Hello', u'Cool', u'Glam']
new_tag_list[u'', u'Hello', u'Cool', u'Glam']

如何摆脱空字符串?

如果列表中有空字符串:

>>> s = [u'', u'Hello', u'Cool', u'Glam']
>>> i = s.index("")
>>> del s[i]
>>> s
[u'Hello', u'Cool', u'Glam']

但如果没有空字符串:

>>> s = [u'Hello', u'Cool', u'Glam']
>>> if s.index(""):
        i = s.index("")
        del s[i]
    else:
        print "new_tag_list has no empty string"

但是这给了:

Traceback (most recent call last):
  File "<pyshell#30>", line 1, in <module>
    if new_tag_list.index(""):
        ValueError: list.index(x): x not in list

为什么会发生这种情况,我该如何解决它?

8 个答案:

答案 0 :(得分:596)

1)几乎是英式风格:

使用in运算符测试状态,然后应用remove方法。

if thing in some_list: some_list.remove(thing)

remove方法只删除第一次出现的thing,以便删除您可以使用while代替if的所有实例。

while thing in some_list: some_list.remove(thing)    
  • 很简单,可能是我的选择。对于小名单(无法抗拒单行)

2)Duck-typedEAFP样式:

这种先发制人问题 - 最后一种态度在Python中很常见。如果对象合适,不要提前测试,只需执行操作并捕获相关的例外:

try:
    some_list.remove(thing)
except ValueError:
    pass # or scream: thing not in some_list!
except AttributeError:
    call_security("some_list not quacking like a list!")

当然,上面例子中的第二个除了条款不仅是有问题的幽默,而且完全没有必要(关键是要为不熟悉这个概念的人说明鸭子打字)。

如果您预计会发生多次事件:

while True:
    try:
        some_list.remove(thing)
    except ValueError:
        break
  • 对于这个特定的用例有点冗长,但在Python中非常惯用。
  • 这比#1
  • 表现更好
  • PEP 463提出了一个较短的语法,用于尝试/除了简单的用法,在这里很方便,但它没有得到批准。

但是,使用contextlib's suppress() contextmanager(在python 3.4中引入),上面的代码可以简化为:

with suppress(ValueError, AttributeError):
    some_list.remove(thing)

同样,如果您预计会发生多次事件:

with suppress(ValueError):
    while True:
        some_list.remove(thing)

3)功能风格:

1993年左右,Python得到lambdareduce()filter()map(),由Lisp黑客提供,他们错过了他们并提交了工作补丁*。您可以使用filter从列表中删除元素:

is_not_thing = lambda x: x is not thing
cleaned_list = filter(is_not_thing, some_list)

有一个可能对您的案例有用的快捷方式:如果您想要过滤掉空项目(实际上项目bool(item) == False,如None,零,空字符串或其他空集​​合,你可以传递None作为第一个参数:

cleaned_list = filter(None, some_list)
  • [更新] :在Python 2.x中,如果第一个参数为{{1,则filter(function, iterable)过去等同于[item for item in iterable if function(item)](或[item for item in iterable if item] }});在Python 3.x中,它现在等同于None。微妙的区别在于过滤器用于返回列表,现在它的工作方式类似于生成器表达式 - 如果您只是遍历已清理的列表并将其丢弃,则可以,但如果您确实需要列表,则必须将{ {1}}使用(item for item in iterable if function(item))构造函数调用。
  • *这些Lispy风格的构造在Python中被认为有点陌生。大约在2005年,Guido was even talking about dropping filter - 以及同伴filter()list()(他们还没有离开,map被移入functools模块,这是值得的看看你是否喜欢high order functions)。

4)数学风格:

List comprehensions在2.0版中引入以来,

PEP 202成为Python中列表操作的首选样式。其背后的基本原理是List comprehensions提供了一种更简洁的方法来在当前使用reducereduce和/或嵌套循环的情况下创建列表。

map()

版本2.4由PEP 289引入了生成器表达式。对于您并不真正需要(或想要)在内存中创建完整列表的情况,生成器表达式更好 - 例如,当您只想一次迭代元素时。如果您只是遍历列表,则可以将生成器表达式视为lazy evaluated列表推导:

filter()

备注

  1. 您可能希望使用不等式运算符cleaned_list = [ x for x in some_list if x is not thing ] 而不是for item in (x for x in some_list if x is not thing): do_your_thing_with(item) the difference is important
  2. 对于暗示列表副本的方法的批评:与流行的看法相反,生成器表达并不总是比列表理解更有效 - 请在抱怨之前进行说明

答案 1 :(得分:12)

try:
    s.remove("")
except ValueError:
    print "new_tag_list has no empty string"

请注意,这只会从列表中删除空字符串的一个实例(因为您的代码也会如此)。您的列表可以包含多个吗?

答案 2 :(得分:5)

如果index找不到搜索到的字符串,则会抛出您看到的ValueError。或 捕获ValueError:

try:
    i = s.index("")
    del s[i]
except ValueError:
    print "new_tag_list has no empty string"

使用find,在这种情况下返回-1。

i = s.find("")
if i >= 0:
    del s[i]
else:
    print "new_tag_list has no empty string"

答案 3 :(得分:3)

Eek,不要做任何复杂的事情:)

只需filter()您的代码。 bool()为空字符串返回False,因此不是

new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)

你应该写

new_tag_list = filter(bool, f1.striplist(tag_string.split(",") + selected_tags))

或者更好的是,将此逻辑放在striplist()中,以便它不会首先返回空字符串。

答案 4 :(得分:3)

添加此答案是为了完整性,尽管它只能在某些条件下使用。

如果您有非常大的列表,从列表末尾删除可以避免CPython内部必须memmove,以便您可以重新排序列表。它可以从列表末尾删除性能,因为在删除后的一个后,它不需要memmove 每个项目( 1)
对于一次性删除,性能差异可能是可以接受的,但如果您有一个大型列表并需要删除许多项目 - 您可能会注意到性能损失。

虽然不可否认,在这些情况下,进行完整列表搜索也可能是性能瓶颈,除非项目主要位于列表的前面。

此方法可用于更有效的删除,只要重新排序列表是可以接受的。 (2)

def remove_unordered(ls, item):
    i = ls.index(item)
    ls[-1], ls[i] = ls[i], ls[-1]
    ls.pop()

如果列表中的item不在,您可能希望避免引发错误。

def remove_unordered_test(ls, item):
    try:
        i = ls.index(item)
    except ValueError:
        return False
    ls[-1], ls[i] = ls[i], ls[-1]
    ls.pop()
    return True
  1. 虽然我使用CPython测试了它,但很可能大多数/所有其他Python实现都使用数组来在内部存储列表。因此,除非他们使用专为有效列表重新调整大小而设计的复杂数据结构,否则它们可能具有相同的性能特征。
  2.   

    一种简单的测试方法,比较从列表前面删除的速度差异,删除最后一个元素:

    python -m timeit 'a = [0] * 100000' 'while a: a.remove(0)'
    
         

    使用:

    python -m timeit 'a = [0] * 100000' 'while a: a.pop()'
    
         

    (给出一个数量级的速度差异,其中第二个例子在CPython和PyPy中更快)。

    1. 在这种情况下,您可以考虑使用set,尤其是如果列表不是为了存储重复项。
      实际上,您可能需要存储可变数据。 t被添加到set。如果可以订购数据,也请检查btree。

答案 5 :(得分:2)

这是另一种抛弃那种方法:

next((some_list.pop(i) for i, l in enumerate(some_list) if l == thing), None)

它不会创建列表副本,不会在列表中进行多次传递,不需要额外的异常处理,并且如果没有匹配则返回匹配的对象或None。唯一的问题是它需要很长的陈述。

通常,在寻找不会抛出异常的单行解决方案时,next()是可行的方法,因为它是支持默认参数的少数Python函数之一。

答案 6 :(得分:0)

你所要做的就是这个

list = ["a", "b", "c"]
    try:
        list.remove("a")
    except:
        print("meow")

但该方法存在问题。你必须把东西放在除外的地方 所以我发现了这个:

list = ["a", "b", "c"]
if "a" in str(list):
    list.remove("a")

答案 7 :(得分:0)

作为一个班轮:

>>> s = [u'', u'Hello', u'Cool', u'Glam']
>>> s.remove('') if '' in s else None # Does nothing if '' not in s
>>> s
['Hello', 'Cool', 'Glam']
>>>