Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:在迭代时从列表中删除项,这些项具有非平凡的删除条件_Python - Fatal编程技术网

Python:在迭代时从列表中删除项,这些项具有非平凡的删除条件

Python:在迭代时从列表中删除项,这些项具有非平凡的删除条件,python,Python,这不是我发现的其他问题的重复,例如: 问题是:给定一个类列表,比如抽象套接字,如果有一种非常简单的方法来确定是否应该删除它们,那么删除它们最适合的方法是什么 sockets = [ socket1, socket2, socket3 ] # whatever for sock in sockets: try: sock.close() except: pass else: remove the socket from t

这不是我发现的其他问题的重复,例如:

问题是:给定一个类列表,比如抽象套接字,如果有一种非常简单的方法来确定是否应该删除它们,那么删除它们最适合的方法是什么

sockets = [ socket1, socket2, socket3 ] # whatever
for sock in sockets:
    try:
        sock.close()
    except:
        pass
    else:
        remove the socket from the list here!
无法从任一链接使用解决方案。以我有限的Python知识,我能想到的“最佳”解决方案是创建一个新列表,其中只添加遇到异常的列表

sockets = [ socket1, socket2, socket3 ] # whatever
newsockets = []
for sock in sockets:
    try:
        sock.close()
    except:
        newsockets.append(sock)
sockets = newsockets
然而,这仍然感觉不对。有更好的办法吗

编辑版主,他忽略了我的明确声明,即被标记为重复的问题不是重复

对于我发布的第一个链接,您不能在列表中使用try/except。
至于第二个链接(它被标记为复制的链接),正如评论所说,这是一个糟糕的解决方案<代码>删除(非散列项或没有uuu eq uuu的项)不起作用。

通常正确的算法是建立一个新列表,然后用新列表替换原始列表,或者在其中切片,如果您希望删除大量套接字:

sockets = [socket1, socket2, socket3] # whatever
new_sockets = []
for sock in sockets:
    try:
        sock.close()
    except:
        new_sockets.append(sock)

sockets[:] = new_sockets
原因是,移除
n
项列表中任意位置的项(例如,使用
sockets.remove
)平均时间复杂度为
O(n)
,如果最终移除
k
项,则总复杂度为
O(kn)
,然而,构建一个新的列表并用新的替换原来的列表将具有
O(n)
规模的时间复杂性,即它不依赖于移除的套接字的数量


或者,由于套接字是可散列的,也许您应该使用一个集合来存储它们。然后,您需要从集合中构造一个新集合,以便可以同时迭代和删除(这里我使用的是一个列表):

创建新列表的时间复杂度为O(n),但
set.discard
的时间复杂度仅为O(1)

避免复制数据结构的另一种方法是对要删除的项使用另一个集合:


如果要删除的项目非常少,则与其他设置示例相比,此设置具有良好的运行时间。

通常正确的算法方法是构建一个新列表,然后用新列表替换原始列表,或者在其中切片,如果您希望删除大量套接字:

sockets = [socket1, socket2, socket3] # whatever
new_sockets = []
for sock in sockets:
    try:
        sock.close()
    except:
        new_sockets.append(sock)

sockets[:] = new_sockets
原因是,移除
n
项列表中任意位置的项(例如,使用
sockets.remove
)平均时间复杂度为
O(n)
,如果最终移除
k
项,则总复杂度为
O(kn)
,然而,构建一个新的列表并用新的替换原来的列表将具有
O(n)
规模的时间复杂性,即它不依赖于移除的套接字的数量


或者,由于套接字是可散列的,也许您应该使用一个集合来存储它们。然后,您需要从集合中构造一个新集合,以便可以同时迭代和删除(这里我使用的是一个列表):

创建新列表的时间复杂度为O(n),但
set.discard
的时间复杂度仅为O(1)

避免复制数据结构的另一种方法是对要删除的项使用另一个集合:

如果要删除的项目很少(如果有的话),此示例的运行时间比其他示例的运行时间要长。

此答案只添加了一点解释,说明了为什么要将结果分配到原始列表的某个部分@Antti Happala已经给出了一些很好的备选方案,可以潜在地改进运行时

当你写作时

sockets = newsockets
您正在将新列表分配给名为
sockets
的变量

sockets[:] = newsockets
实际上,您正在用新列表替换相同列表的条目

如果您以前对
sockets
列表有其他引用,则差异会变得更加明显,如下所示:

s = sockets
然后,在没有切片的情况下分配后,
s
仍将指向没有移除任何套接字的旧列表,
sockets
将引用新列表

使用切片版本,
s
sockets
将在删除某些元素后引用相同的更新列表

通常,这种就地替换是您想要的,但是,有时您可能特别希望
s
sockets
引用列表的不同版本,在这种情况下,您不应该指定给列表片段。这要看情况而定。

这个答案只是补充了一点解释,说明了为什么要将结果分配给原始列表的一部分@Antti Happala已经给出了一些很好的备选方案,可以潜在地改进运行时

当你写作时

sockets = newsockets
您正在将新列表分配给名为
sockets
的变量

sockets[:] = newsockets
实际上,您正在用新列表替换相同列表的条目

如果您以前对
sockets
列表有其他引用,则差异会变得更加明显,如下所示:

s = sockets
然后,在没有切片的情况下分配后,
s
仍将指向没有移除任何套接字的旧列表,
sockets
将引用新列表

使用切片版本,
s
sockets
将在删除某些元素后引用相同的更新列表

通常,这种就地替换是您想要的,但是,有时您可能特别希望
s
sockets
引用列表的不同版本,在这种情况下,您不应该这样做