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

Zey*_*nel 218 python list

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

self.response.get_all("selected_tags")
Run Code Online (Sandbox Code Playgroud)

我把它们组合成这样:

tag_string = new_tag
new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)
Run Code Online (Sandbox Code Playgroud)

(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']
Run Code Online (Sandbox Code Playgroud)

如何摆脱空字符串?

如果列表中有空字符串:

>>> s = [u'', u'Hello', u'Cool', u'Glam']
>>> i = s.index("")
>>> del s[i]
>>> s
[u'Hello', u'Cool', u'Glam']
Run Code Online (Sandbox Code Playgroud)

但是如果没有空字符串:

>>> 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"
Run Code Online (Sandbox Code Playgroud)

但这给了:

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
Run Code Online (Sandbox Code Playgroud)

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

Pau*_*ine 644

1)几乎英国风格:

使用in操作员测试存在,然后应用该remove方法.

if thing in some_list: some_list.remove(thing)
Run Code Online (Sandbox Code Playgroud)

remove方法将仅删除第一次出现的thing,以便删除您可以使用的所有实例,while而不是if.

while thing in some_list: some_list.remove(thing)    
Run Code Online (Sandbox Code Playgroud)
  • 很简单,可能是我的选择.对于小清单(无法抗拒单行)

2)Duck-typed,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!")
Run Code Online (Sandbox Code Playgroud)

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

如果你期望多次出现的事情:

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

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

with suppress(ValueError, AttributeError):
    some_list.remove(thing)
Run Code Online (Sandbox Code Playgroud)

同样,如果您期望多次出现的事情:

with suppress(ValueError):
    while True:
        some_list.remove(thing)
Run Code Online (Sandbox Code Playgroud)

3)功能风格:

1993年左右,巨蟒有lambda,reduce(),filter()map(),一个礼貌的Lisp黑客谁错过了他们,并提交工作补丁*.您可以使用filter从列表中删除元素:

is_not_thing = lambda x: x is not thing
cleaned_list = filter(is_not_thing, some_list)
Run Code Online (Sandbox Code Playgroud)

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

cleaned_list = filter(None, some_list)
Run Code Online (Sandbox Code Playgroud)
  • [更新]:在Python 2.x中,filter(function, iterable)曾经相当于[item for item in iterable if function(item)](或者[item for item in iterable if item]如果第一个参数是None); 在Python 3.x中,它现在相当于(item for item in iterable if function(item)).微妙的区别在于过滤器用于返回列表,现在它的工作方式类似于生成器表达式 - 如果您只是遍历清理后的列表并将其丢弃,这是可以的,但如果您确实需要列表,则必须将filter()呼叫括起来与list()构造函数.
  • *这些Lispy风格的构造在Python中被认为有点陌生.2005年左右,圭多甚至被谈论下降filter -与同伴一起mapreduce(他们不走了,但还没有reduce被搬进了functools模块,这是值得一试,如果你喜欢高阶函数).

4)数学风格:

列表内涵成为在Python列表操作的首选风格,因为在2.0版本中引入PEP 202.其背后的理由是,列表解析提供了更简洁的方式来创建情况列表,其中map()filter()和/或嵌套循环将目前被使用.

cleaned_list = [ x for x in some_list if x is not thing ]
Run Code Online (Sandbox Code Playgroud)

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

for item in (x for x in some_list if x is not thing):
    do_your_thing_with(item)
Run Code Online (Sandbox Code Playgroud)

笔记

  1. 您可能想要使用不等式运算符!=而不是is not(差异很重要)
  2. 对于暗示列表副本的方法的批评者:与流行的看法相反,生成器表达式并不总是比列表理解更有效 - 请在抱怨之前进行描述

  • 我可以建议省略(2)中的AttributeError处理吗?它会分散注意力,而不会在其他部分(或同一部分的其他部分)处理.更糟糕的是,有人可能会复制该代码而没有意识到他们过于积极地压制异常.原始问题假定一个列表,答案也应该如此. (2认同)
  • 超级全面的回答!很高兴将其按“风格”分为不同的部分。谢谢! (2认同)
  • 哪个最快? (2认同)

qwe*_*url 14

作为单行:

>>> 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']
>>> 
Run Code Online (Sandbox Code Playgroud)


Tim*_*ker 12

try:
    s.remove("")
except ValueError:
    print "new_tag_list has no empty string"
Run Code Online (Sandbox Code Playgroud)

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


Dan*_*ite 6

这是另一种简单的方法:

next((some_list.pop(i) for i, l in enumerate(some_list) if l == thing), None)
Run Code Online (Sandbox Code Playgroud)

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

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


phi*_*hag 5

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

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

或者使用find,在这种情况下返回-1.

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

  • 时间Pietscker的`remove()`方法更直接:它直接显示代码的意图(确实不需要中间索引`i`). (2认同)

dfi*_*ter 5

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

只是filter()你的标签。 bool()返回False空字符串,所以而不是

new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)
Run Code Online (Sandbox Code Playgroud)

你应该写

new_tag_list = filter(bool, f1.striplist(tag_string.split(",") + selected_tags))
Run Code Online (Sandbox Code Playgroud)

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


ide*_*n42 5

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

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

尽管不可否认,在这些情况下,执行完整列表搜索也可能是性能瓶颈,除非项目大部分位于列表的前面。


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

def remove_unordered(ls, item):
    i = ls.index(item)
    ls[-1], ls[i] = ls[i], ls[-1]
    ls.pop()
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)
  1. 虽然我用 CPython 对此进行了测试,但很可能大多数/所有其他 Python 实现都使用数组在内部存储列表。因此,除非他们使用专为有效调整列表大小而设计的复杂数据结构,否则他们可能具有相同的性能特征。

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

python -m timeit 'a = [0] * 100000' 'while a: a.remove(0)'
Run Code Online (Sandbox Code Playgroud)

和:

python -m timeit 'a = [0] * 100000' 'while a: a.pop()'
Run Code Online (Sandbox Code Playgroud)

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

  1. 在这种情况下,您可以考虑使用set,尤其是在列表不打算存储重复项的情况下。
    在实践中,尽管您可能需要存储无法添加到set. 还要检查 btree 是否可以订购数据。