如何删除列表中的项目?
我从self.response.get("new_tag")
和checkbox字段中的selected_tags
表单文本字段获取new_tag
self.response.get_all("selected_tags")
我把它们合并为这样:
tag_string = new_tag new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)
( f1.striplist
是一个函数,用于f1.striplist
列表中的string中的空格。)
但是,如果tag_list
为空(不input新的标签),但有一些selected_tags
,则new_tag_list
包含一个空string" "
。
例如,从logging.info
:
new_tag selected_tags[u'Hello', u'Cool', u'Glam'] new_tag_list[u'', u'Hello', u'Cool', u'Glam']
我如何摆脱空的string?
如果列表中有空string:
>>> s = [u'', u'Hello', u'Cool', u'Glam'] >>> i = s.index("") >>> del s[i] >>> s [u'Hello', u'Cool', u'Glam']
但是,如果没有空string:
>>> 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
为什么会发生这种情况,我该如何解决这个问题?
1)几乎英式风格:
使用in
运算符testing存在性,然后应用remove
方法。
if thing in some_list: some_list.remove(thing)
remove
方法将只删除事件的第一个事件,以便删除所有可以使用的事件while
不是if
。
while thing in some_list: some_list.remove(thing)
- 很简单,可能是我的select。对于小名单(不能抗拒单线)
2) 鸭式 , EAFP风格:
在Python中,这种先发问后问题的态度很常见。 如果对象适合,而不是事先进行testing,只需执行操作并捕获相关的exception:
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中非常习惯。
- 这比#1performance更好
- PEP 463提出了一个简短的try / except语法,除了简单的用法,在这里很方便,但是没有被批准。
但是,通过使用contextlib的suppress()上下文pipe理器 (在Python 3.4中引入),上面的代码可以简化为:
with suppress(ValueError, AttributeError): some_list.remove(thing)
再一次,如果你期望多次发生的事情:
with suppress(ValueError): while True: some_list.remove(thing)
3)function风格:
在1993年左右,Python得到了lambda
, reduce()
, 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
,零,空string或其他空集合),你可以通过None作为第一个参数:
cleaned_list = filter(None, some_list)
- [更新] :在Python 2.x中,如果第一个参数是
None
,filter(function, iterable)
就相当于[item for item in iterable if function(item)]
(或[item for item in iterable if item]
); 在Python 3.x中,它现在等同于(item for item in iterable if function(item))
,则(item for item in iterable if function(item))
。 细微的区别在于filter用于返回一个列表,现在它像一个生成器expression式那样工作 – 如果您只是迭代已清除的列表并丢弃它,那么这样做是可以的,但是如果您真的需要列表,则必须将filter()
使用list()
构造函数进行调用。 - *这些Lispy风格的构造在Python中被认为是一个小外星人。 在2005年左右, Guido甚至在谈论下降
filter
– 以及同伴map
和reduce
(他们还没有消失,但reduce
被转移到functools模块,这是值得一看,如果你喜欢高阶函数 )。
4)math风格:
自从PEP 202在2.0版中引入以来,列表parsing成为Python中列表操作的首选样式。 其背后的基本原理是,列表推导提供了一个更简洁的方式来创build列表,在当前使用map()
和filter()
和/或嵌套循环的情况下。
cleaned_list = [ x for x in some_list if x is not thing ]
生成器expression式是由PEP 289在2.4版中引入的。 生成器expression式适用于您并不真正需要(或者想要)在内存中创build完整列表的情况,比如当您只想一次遍历元素时。 如果你只是迭代列表,你可以把一个生成器expression式看作一个懒惰的评估列表理解:
for item in (x for x in some_list if x is not thing): do_your_thing_with(item)
- 看到GvR的 这个Python历史博客文章。
- 这个语法的灵感来自math中的set-builder符号 。
- Python 3也设置和字面理解 。
笔记
- 你可能要使用不等式运算符
!=
而is not
( 差别很重要 ) - 批评方法意味着列表副本:与stream行的观念相反,生成器expression式并不总是比列表parsing更有效 – 请在投诉之前进行configuration
try: s.remove("") except ValueError: print "new_tag_list has no empty string"
请注意,这只会从你的列表中删除空string的一个实例(因为你的代码也会)。 你的列表可以包含多个?
如果index
没有findsearch到的string,它会ValueError
你正在看到的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"
Eek,不要做任何复杂的事情:)
只是filter()
你的标签。 bool()
为空string返回False
,所以不是
new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)
你应该写
new_tag_list = filter(bool, f1.striplist(tag_string.split(",") + selected_tags))
或者更好,把这个逻辑放在striplist()
这样它不会首先返回空string。
添加这个答案的完整性,虽然它只能在某些条件下使用。
如果你有很大的列表,从列表的末尾移除可以避免CPython内部必须移除的情况,在这种情况下,你可以重新排列列表。 它提供了一个性能增益从列表的末尾移除,因为它不需要在删除之后删除每个项目 – 返回一步(1) 。
对于一次性清除,性能差异可能是可以接受的,但是如果您有大量清单并需要清除很多项目 – 您可能会注意到性能受到影响。
虽然承认,在这种情况下,进行完整的列表search也可能是性能瓶颈,除非项目大部分在列表的前面。
这种方法可以用于更有效的去除,
只要重新排列名单是可以接受的。 (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
- 当我用CPythontesting这个时,很可能大多数/所有其他Python实现都使用一个数组来存储内部列表。 所以除非他们使用一个复杂的数据结构来devise高效的列表resize,否则它们可能具有相同的性能特征。
一个简单的方法来testing这个,比较从删除列表前面的速度差异与删除最后一个元素:
python -m timeit 'a = [0] * 100000' 'while a: a.remove(0)'
附:
python -m timeit 'a = [0] * 100000' 'while a: a.pop()'
(给出了一个数量级的速度差异,在CPython和PyPy中第二个例子更快)。
- 在这种情况下,您可以考虑使用一个
set
,特别是如果列表不是用来存储重复的。
实际上,虽然您可能需要存储不能添加到set
可变数据。 如果可以订购数据,也检查btree的。
这里有另外一种方法来抛出:
next((some_list.pop(i) for i, l in enumerate(some_list) if l == thing), None)
它不会创build列表副本,不会在列表中进行多次传递,也不需要额外的exception处理,并返回匹配的对象,如果不匹配,则返回None。 唯一的问题是,这是一个长期的声明。
一般来说,在寻找一个不会抛出exception的单线解决scheme时,next()是一种可行的方法,因为它是less数支持默认参数的Python函数之一。
你所要做的就是这个
list = ["a", "b", "c"] try: list.remove("a") except: print("meow")
但是这个方法有一个问题。 你必须把东西放在除了地方,所以我发现这一点:
list = ["a", "b", "c"] if "a" in str(list): list.remove("a")