[英]Can not remove similar elements from two lists
我有数组一:a1 = [1,2,3],数组二:a2 = [1,2,3]。 我必须比较这两个数组并从 a1 中删除所有相似的元素。 同时我必须返回a1
并且我不能使用这些是要求的附加库。 我试图以这种方式做到这一点:
for i in a1:
for j in a2:
if i == j:
a1.remove(j)
这里的问题是它返回 [2] 而不是 [](空数组)
附注。 我知道类似的问题,但我在那里找不到解决方案如何在迭代时从列表中删除项目?
我会为此使用 Sets
>>> a1 = [1,2,3,4]
>>> a2 = [1,2,3,4]
>>> a1 = list(set(a1) - set(a2))
>>> a1
[]
>>> a1 = [1,2,3,4,5]
>>> a1 = list(set(a1) - set(a2))
>>> a1
[5]
对于较小的数据集,这可能效率低下,但对于较大的数据集,我发现它的效率要高得多(基于时间)。
使用 timeit 和 time 定时运行。 使用另一个答案中的方法
time python -m timeit -n 10 -s "a1 = range(100000); a2=range(100000) " -s "for i in a1:" -s " if i in a2: a1.remove(i)"
10 loops, best of 3: 0.0954 usec per loop
real 2m34.144s
user 2m32.468s
sys 0m0.468s
使用上述方法定时运行
time python -m timeit -n 10 "a1 = range(1000000); a2=range(1000000) ; a1 = list(set(a1) - set(a2)) ; "
10 loops, best of 3: 109 msec per loop
real 0m3.453s
user 0m3.090s
sys 0m0.350s
尝试这个:
for i in a1:
if i in a2:
a1.remove(i)
有一百种方法可以解决这个问题,但这是我最喜欢的一种:
a1 = list(filter(lambda e: e not in a2, a1))
您可能可以通过以下方式做到这一点:
a1 = [x for x in a1 if x not in a2]
你会得到[2]
的原因是你正在从a
中删除元素,而继续迭代a
这很可能总是产生问题。
这是我们所期望的:
# sudo code
a[0] == b[0] ? if not then continue iterating array b; if yes, a.remove(b[0])
a[0] == b[1] ? if not then continue iterating array b; if yes, a.remove(b[1])
...
好吧,但程序不会像我们预期的那样做:(
据推测,这与for
循环在 python 中的工作机制有关。 我对此做了一些简短的研究,但没有找到确切的答案。 然而,根据[2]的结果,地下可能发生的事情如下(免责声明:我没有查源代码,我鼓励你,所以下面的推论可能是错误的......)
因为我们都知道 Python 来自 C,所以 Python 的for
循环只是 C 的简写。 在 C 中,通常我们按索引进行迭代,例如for (int index=0; index < size; index++)
。 在 Python 中,我们似乎省略了索引,只生成了值,但很可能 Python 的for
循环仍然在带索引的for
循环下运行,只是我们在那里没有看到它。 这种机制的结果是,当您在第一次迭代中执行a.remove(1)
时,您将a
的长度缩短到 2,同时索引从0
增加到1
。 在第二次迭代期间,程序正在寻找a[1]
,其中1
是从0
递增的索引。 由于您删除了a
的第一个元素,当前a[1]
变成了前a[2]
,它指向值3
。 然后,您再次将 a 中的3
与b
中a
所有值进行比较,那么它肯定可以找到匹配项并且也会删除 3。 现在它打破了条件index < size
(实际上 index 已经大于 size 因为在两次删除后size
已经减少到1
,并且index
会从1
增加到2
)。 因此,迭代被称为停止。 现在,当您评估a
它会产生[2]
,因为原始的a[1]
2
被跳过了该过程。
可以说明这一点的示例代码如下,我已经尝试过:
a = [1, 2, 3]
for n in a:
print(n)
a.remove(n)
你会看到只打印了1
和3
,这证明2
确实被跳过了。
这可以通过以下代码更好地解释:-
for i in a1:
print('a1 = ', a1)
print('i = ', i)
if i in a2:
a1.remove(i)
print('After removing, a1 = ', a1)
上面的代码输出
a1 = [1, 2, 3]
i = 1
After removing, a1 = [2, 3]
a1 = [2, 3]
i = 3
After removing, a1 = [2]
可以看出,在第一次删除 1 之后,现在 i 变为 3,而不是 2。这是因为 Python 在循环开始时修复了迭代器的值。 在这种情况下,它将 i 从 0 固定到 2,但是由于a1.remove()
减少了 a1 的长度,它应该检查 2,但它正在检查第一个索引,即a1.remove()
i = i - 1
不能放在这里因为它不起作用。 为此,可以使用以下代码
i = 0
while i < len(a1):
if a1[i] in a2:
a1.remove(a1[i])
i = i - 1
i = i + 1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.