如何在不使用 for 循环的情况下从列表中删除元素?
Posted
技术标签:
【中文标题】如何在不使用 for 循环的情况下从列表中删除元素?【英文标题】:How to remove element from list without using for loop? 【发布时间】:2022-01-22 15:37:03 【问题描述】:我有两个元组列表,A
和 B
,用于存储数据 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 文件中读取对象数组中特定键的值