How to delete an item in a list if it exists?
我从带有复选框字段的
1 | self.response.get_all("selected_tags") |
我把它们组合成这样:
1 2 | tag_string = new_tag new_tag_list = f1.striplist(tag_string.split(",") + selected_tags) |
(
但是在
例如,从
1 2 3 | new_tag selected_tags[u'Hello', u'Cool', u'Glam'] new_tag_list[u'', u'Hello', u'Cool', u'Glam'] |
如何摆脱空字符串?
如果列表中有空字符串:
1 2 3 4 5 | >>> s = [u'', u'Hello', u'Cool', u'Glam'] >>> i = s.index("") >>> del s[i] >>> s [u'Hello', u'Cool', u'Glam'] |
但是如果没有空字符串:
1 2 3 4 5 6 | >>> 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" |
但这给了:
1 2 3 4 | 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 |
为什么会发生这种情况,我该如何解决?
1)几乎英国风格:
使用
1 | if thing in some_list: some_list.remove(thing) |
1 | while thing in some_list: some_list.remove(thing) |
- 很简单,可能是我的选择。对于小清单(无法抗拒单行)
2)Duck-typed,EAFP风格:
这种拍摄优先问题 - 最后的态度在Python中很常见。如果对象适合,而不是提前测试,只需执行操作并捕获相关的例外:
1 2 3 4 5 6 | 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!") |
当然,上面例子中的第二个除了条款不仅具有可疑的幽默,而且完全没有必要(关键是要为不熟悉这个概念的人说明鸭子打字)。
如果你期望多次出现的事情:
1 2 3 4 5 | while True: try: some_list.remove(thing) except ValueError: break |
- 对于这个特定的用例有点冗长,但在Python中非常惯用。
- 这比#1表现更好
- PEP 463提出了一个较短的语法,用于尝试/除了简单的用法,这在这里很方便,但它没有得到批准。
但是,使用contextlib的suppress()contextmanager(在python 3.4中引入),上面的代码可以简化为:
1 2 | with suppress(ValueError, AttributeError): some_list.remove(thing) |
同样,如果您期望多次出现的事情:
1 2 3 | with suppress(ValueError): while True: some_list.remove(thing) |
3)功能风格:
大约在1993年,Python获得了
1 2 | is_not_thing = lambda x: x is not thing cleaned_list = filter(is_not_thing, some_list) |
有一个可能对你的情况有用的快捷方式:如果你想过滤掉空项目(事实上
1 | cleaned_list = filter(None, some_list) |
-
[update]:在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)) 。微妙的区别在于过滤器用于返回列表,现在它的工作方式类似于生成器表达式 - 如果您只是在清理列表上进行迭代并丢弃它,这是可以的,但如果您确实需要列表,则必须将< x8>使用list() 构造函数调用。 -
*这些Lispy风格的构造在Python中被认为有点陌生。 2005年左右,Guido甚至在谈论删除
filter - 以及同伴map 和reduce (它们还没有消失,但reduce 被移入functools模块,如果你喜欢高阶命令,这值得一看功能)。
4)数学风格:
自从PEP 202在2.0版本中引入以来,列表推导成为Python中列表操作的首选样式。其背后的基本原理是列表推导提供了一种更简洁的方法来在
1 | cleaned_list = [ x for x in some_list if x is not thing ] |
生成器表达式由PEP 289在2.4版本中引入。生成器表达式更适用于您不需要(或想要)在内存中创建完整列表的情况 - 例如,当您只想迭代元素之一时一时间如果您只是在列表上进行迭代,则可以将生成器表达式视为惰性求值列表推导:
1 2 | for item in (x for x in some_list if x is not thing): do_your_thing_with(item) |
- 请参阅GvR的Python历史博客文章。
- 此语法的灵感来自数学中的set-builder符号。
- Python 3也设置和理解了解。
笔记
1 2 3 4 | try: s.remove("") except ValueError: print"new_tag_list has no empty string" |
请注意,这只会从列表中删除空字符串的一个实例(因为您的代码也会如此)。 您的列表可以包含多个吗?
如果
捕获ValueError:
1 2 3 4 5 | try: i = s.index("") del s[i] except ValueError: print"new_tag_list has no empty string" |
或者使用
1 2 3 4 5 | i = s.find("") if i >= 0: del s[i] else: print"new_tag_list has no empty string" |
添加此答案是为了完整性,尽管它仅在某些条件下可用。
如果您有非常大的列表,从列表末尾删除可以避免CPython内部必须
对于一次性删除,性能差异可能是可接受的,但如果您有一个大型列表并需要删除许多项目 - 您可能会注意到性能损失。
虽然不可否认,在这些情况下,进行完整列表搜索也可能是性能瓶颈,除非项目主要位于列表的前面。
只要重新排序列表是可接受的,此方法可用于更有效的删除。 (2)
1 2 3 4 | def remove_unordered(ls, item): i = ls.index(item) ls[-1], ls[i] = ls[i], ls[-1] ls.pop() |
当
1 2 3 4 5 6 7 8 | 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 |
A simple way to test this, compare the speed difference from removing from the front of the list with removing the last element:
1 python -m timeit 'a = [0] * 100000' 'while a: a.remove(0)'With:
1 python -m timeit 'a = [0] * 100000' 'while a: a.pop()'(gives an order of magnitude speed difference where the second example is faster with CPython and PyPy).
Eek,不要做任何复杂的事情:)
只需
1 | new_tag_list = f1.striplist(tag_string.split(",") + selected_tags) |
你应该写
1 | new_tag_list = filter(bool, f1.striplist(tag_string.split(",") + selected_tags)) |
或者更好的是,将此逻辑放在
抛出那里是另一种单线方法:
1 | next((some_list.pop(i) for i, l in enumerate(some_list) if l == thing), None) |
它不会创建列表副本,不会通过列表进行多次传递,不需要额外的异常处理,并返回匹配的对象,如果没有匹配则返回None。唯一的问题是它是一个冗长的陈述。
通常,在寻找不会抛出异常的单行解决方案时,next()是要走的路,因为它是支持默认参数的少数Python函数之一。
你所要做的就是这个
1 2 3 4 5 | list = ["a","b","c"] try: list.remove("a") except: print("meow") |
但那种方法有问题。你必须把东西放在除外的地方
所以我发现了这个:
1 2 3 | list = ["a","b","c"] if"a" in str(list): list.remove("a") |