在可能出现重复值的 python 中从另一个列表中减去一个列表

Subtracting one list from another in python where duplicate values may occur

我想从另一个数组中删除一个数组的内容。

array_2 = ['one' , "two" , "one", "three", "four"]
array_1 = ['one', "two"]

我第一个想到的是使用列表comprehensions

array_3 = [x for x in array_2 if x not in array_1]

但是这会删除重复项 结果:['three', 'four']

我只想从数组中删除 "one" 一次,因为我正在寻找列表减法。所以我希望结果是:['one', 'three', 'four'].

实现此目的的良好 pythonic 方法是什么?

尝试 Counter 来自 collections:

from collections import Counter

array_2 = ['one' , "two" , "one", "three", "four"]
array_1 = ['one', "two"]

list((Counter(array_2) - Counter(array_1)).elements())

输出

['one', 'three', 'four']

您可以使用列表的remove方法:

array_2 = ['one' , "two" , "one", "three", "four"]
array_1 = ['one', "two"]

# copy list
array_3 = array_2[:]

for element in array_1:
    try:
        array_3.remove(element)
    except ValueError:
        pass
print(array_3)
# ['one', 'three', 'four']

Counter 对象非常适合这个。

In [1]: from collections import Counter                                                                                                                                      

In [2]: array_2 = ['one' , "two" , "one", "three", "four"]                                                                                                                   

In [3]: array_1 = ['one', "two"]                                                                                                                                             

In [4]: a2 = Counter(array_2)                                                                                                                                                

In [5]: a1 = Counter(array_1)                                                                                                                                                

In [6]: a2 - a1                                                                                                                                                              
Out[6]: Counter({'one': 1, 'three': 1, 'four': 1})

如果您想要一个列表,您可以使用以下方法展平 Counter

In [7]: list((a2-a1).elements())                                                                                                                                             
Out[7]: ['one', 'three', 'four']

结合使用 map 函数和 lambda 可以解决您的任务:

map(lambda x: array_2.remove(x) if x in array_2 else None, array_1)

这将直接更改 array_2,结果将是:

print(array_2)
# ['one', 'three', 'four']

我就把上面已经给出的优秀解法收集起来

如果您关心保持 array_2 中元素的原始顺序,那么我认为您必须使用 remove:

array_1 = ['one', 'two']
array_2 = ['one', 'two', 'one', 'three', 'four']
array_3 = list(array_2)
for x in array_1:
    try:
        array_3.remove(x)
    except ValueError:
        pass
print(array_3)

如果元素的最终顺序是什么并不重要,那么使用 Counter 会更有效率,因为它只在两个列表上循环一次:

from collections import Counter

array_1 = ['one', 'two']
array_2 = ['one', 'two', 'one', 'three', 'four']
array_3 = list((Counter(array_2) - Counter(array_1)).elements())
print(array_3)