如何删除一个项目在一个列表,如果它存在?

我得到new_tag从窗体文本字段与self.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_tagsnew_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

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

633682 次浏览
如果index没有找到搜索的字符串,它会抛出你所看到的ValueError。要么 catch 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"
try:
s.remove("")
except ValueError:
print "new_tag_list has no empty string"

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

1)近乎英式风格:

使用in操作符测试是否存在,然后应用remove方法。

if thing in some_list: some_list.remove(thing)

__abc0方法将只删除第一次出现的thing,为了删除所有出现的while,你可以使用while代替if

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

2) 提供EAFP样式:

这种先开枪,后提问的态度在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!")

当然,上面例子中的第二个except子句不仅幽默有问题,而且完全没有必要(重点是为不熟悉这个概念的人演示duck typing)。

如果你期望事物多次出现:

while True:
try:
some_list.remove(thing)
except ValueError:
break
  • 对于这个特定的用例来说有点啰嗦,但在Python中非常习惯。
  • 它的性能比#1要好
  • PEP 463提出了一个更短的try/语法,除了简单的用法,在这里会很方便,但它没有被批准。

然而,使用Contextlib的suppress()上下文管理器(在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(),这是由一个口齿不清黑客提供的,他错过了它们,并提交了工作补丁*。你可以使用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, filter(function, iterable)以前等价于[item for item in iterable if function(item)](如果第一个参数是None,则等价于[item for item in iterable if item]);在Python 3中。x,它现在等价于(item for item in iterable if function(item))。细微的区别是,过滤器用于返回一个列表,现在它像生成器表达式一样工作——如果你只是迭代已清理的列表并丢弃它,这是OK的,但如果你真的需要一个列表,你必须用list()构造函数将filter()调用包围起来。
  • *这些带有Lispy味道的构造在Python中被认为有点异类。大约在2005年,Guido甚至说要放弃filter -以及同伴mapreduce(它们还没有消失,但reduce被移到functools模块,如果你喜欢高阶函数,值得一看)。

4)数学风格:

自2.0版由PEP 202引入以来,列表理解成为Python中列表操作的首选样式。它背后的原理是,列表推导式提供了一种更简洁的方式来创建列表,在当前将使用map()filter()和/或嵌套循环的情况下。

cleaned_list = [ x for x in some_list if x is not thing ]

生成器表达式在2.4版由PEP 289引入。生成器表达式更适合于不需要(或不希望)在内存中创建完整列表的情况——例如,当您只想每次迭代一个元素时。如果你只是在列表上迭代,你可以把生成器表达式看作懒惰的评估列表推导式:

for item in (x for x in some_list if x is not thing):
do_your_thing_with(item)

笔记

  1. 你可能想使用不等式运算符!=而不是is not (区别很重要)
  2. 对于包含列表副本的方法的批评者:与流行的观点相反,生成器表达式并不总是比列表推导更有效-在抱怨之前请先进行剖析

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()中,这样它一开始就不会返回空字符串。

这里有另一个简单的方法:

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

它不创建列表副本,不多次遍历列表,不需要额外的异常处理,并返回匹配的对象,如果不匹配则返回None。唯一的问题是这句话太长了。

一般来说,在寻找不抛出异常的一行程序解决方案时,next()是最佳选择,因为它是少数几个支持默认实参的Python函数之一。

添加这个答案是为了完整性,尽管它只在某些条件下可用。

如果你有一个非常大的列表,从列表末尾删除可以避免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实现都使用数组在内部存储列表。因此,除非它们使用为有效调整列表大小而设计的复杂数据结构,否则它们可能具有相同的性能特征。

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

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,特别是如果列表不是用来存储重复项的。在实践中,你可能需要存储不能添加到set的可变数据。还要检查btree的数据是否可以排序。

你要做的就是这个

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

但是这个方法有一个问题。你必须在除号上放点东西 所以我找到了这个:

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

作为一行:

>>> 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']
>>>