如何在不使用 for 循环的情况下从列表中删除元素?

Posted

技术标签:

【中文标题】如何在不使用 for 循环的情况下从列表中删除元素?【英文标题】:How to remove element from list without using for loop? 【发布时间】:2022-01-22 15:37:03 【问题描述】:

我有两个元组列表,AB,用于存储数据 id 对,如果 (x,y)(y,x)B 中,我想从 A 中删除对也在A

我尝试使用下面的 for 循环来做到这一点,

A = [(321, 33), (56, 991), (645, 2), (8876, 556)]
B = [(33, 321), (645, 2)]

for pair in B:
    if pair in A: 
        A.remove(pair)
    elif (pair[1], pair[0]) in A:
        A.remove((pair[1], pair[0]))

print(A)  # [(56, 991), (8876, 556)]

但是当列表中的元素很大时,这段代码运行很慢。

所以我想让这段代码更快,可能避免使用 for 循环或完全不同的方式。 有人可以帮我解决这个问题吗?

【问题讨论】:

0) 不要用户删除。每次尝试匹配要删除的值时,您都在遍历整个列表。使用索引值遍历您的列表; 1) 哪个列表更大,A 还是 B?目前您正在对 B 进行一次迭代,对 A 进行多次迭代(len(B) 次); 2)你能以某种方式使 A 排序吗? 3)不要 听起来你首先使用集合而不是列表可能更有意义;并且可能是frozensets 而不是元组。 【参考方案1】:

如果A 具有唯一项,您可以将两个列表都转换为集合并使用集合差异,但需要注意的是您将反向元组添加到B_set

set_B = set(B).union([(j,i) for (i,j) in B])
out = list(set(A) - set_B)

输出:

[(321, 33), (645, 2)]

如果A 没有唯一项并且您想保留重复项,则可以对第二行使用列表推导:

set_B = set(B).union([(j,i) for (i,j) in B])
out = [tpl for tpl in A if tpl in set_B]

【讨论】:

@AppleBS 我的意思是真正的性能将显示在大型列表中。我针对 len(A)=1000, len(B)=100 列表运行了我的解决方案和 OP 的解决方案,我的解决方案在 159us 时比 9.39 ms 快了 58 倍。 是的,你是对的。我收回我的评论。【参考方案2】:

假设您使用集合而不是列表,并且第二个集合包含元素的两种变体((x, y)(x, y))...

A = (321, 33), (56, 991), (645, 2), (8876, 556)
B = (33, 321), (645, 2), (321, 33), (2, 645)

你只需要一个集合减法:

print(A - B)

【讨论】:

【参考方案3】:

不是删除,而是通过排除公共元素来创建一个新列表:

[(x,y) for x,y in A if (x,y) not in B and (y,x) not in B]

输出:

[(56, 991), (8876, 556)]

【讨论】:

[(x, y) for x, y in A if (x, y) not in B and (y, x) not in B] 我对您的代码与 kalcium 的代码进行了简单的基准测试。循环 100000 次时,您的代码在 145 毫秒和 101 毫秒时明显慢。

以上是关于如何在不使用 for 循环的情况下从列表中删除元素?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 for 循环的情况下从 appsettings 文件中读取对象数组中特定键的值

从Ruby中的数组中删除重复元素

在 PySpotify 中,试图在不知道曲目在播放列表中的位置的情况下从播放列表中删除曲目

如何在不使用 foreach 循环的情况下从视图访问模型

如何在不使用提交的情况下从下拉列表中选择值

如何在不清除整个队列的情况下从 Resque 队列中删除特定作业?