如何删除列表中的项目?

我从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得到了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 ,零,空string或其他空集​​合),你可以通过None作为第一个参数:

 cleaned_list = filter(None, some_list) 
  • [更新] :在Python 2.x中,如果第一个参数是Nonefilter(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 – 以及同伴mapreduce (他们还没有消失,但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也设置和字面理解 。

笔记

  1. 你可能要使用不等式运算符!=is not ( 差别很重要 )
  2. 批评方法意味着列表副本:与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 

  1. 当我用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中第二个例子更快)。

  1. 在这种情况下,您可以考虑使用一个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")