我想取列表x和y的差值:

>>> x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> y = [1, 3, 5, 7, 9]  
>>> x - y
# should return [0, 2, 4, 6, 8]

当前回答

其他解决方案都存在以下几个问题之一:

它们不能维持秩序,或者 它们不删除精确的元素计数,例如,对于x =[1,2,2,2]和y =[2,2],它们将y转换为一个集合,然后删除所有匹配的元素(只留下[1])或删除每个唯一元素中的一个(留下[1,2,2]),当正确的行为是删除2两次,留下[1,2],或者 它们做O(m * n)个功,而最优解做O(m + n)个功

Alain和Counter在解决第2和第3个问题上是正确的,但这个解决方案将失去秩序。保持顺序的解决方案(在要删除的值列表中重复n次,删除每个值的前n个副本)是:

from collections import Counter

x = [1,2,3,4,3,2,1]  
y = [1,2,2]  
remaining = Counter(y)

out = []
for val in x:
    if remaining[val]:
        remaining[val] -= 1
    else:
        out.append(val)
# out is now [3, 4, 3, 1], having removed the first 1 and both 2s.

在网上试试!

要使它删除每个元素的最后副本,只需将for循环改为for val in reversed(x):并在退出for循环后立即添加out.reverse()。

根据y的长度构造Counter为O(n),根据x的长度迭代x为O(n), Counter隶属度测试和突变为O(1),而list。append被平摊为O(1)(一个给定的append可以是O(n),但对于许多追加,整体大O平均为O(1),因为越来越少的追加需要重新分配),所以所做的总体功是O(m + n)。

你还可以通过测试来确定y中是否有任何元素没有从x中移除:

remaining = +remaining  # Removes all keys with zero counts from Counter
if remaining:
    # remaining contained elements with non-zero counts

其他回答

这是一个“集合减法”操作。使用设定的数据结构。

在Python 2.7中:

x = {1,2,3,4,5,6,7,8,9,0}
y = {1,3,5,7,9}
print x - y

输出:

>>> print x - y
set([0, 8, 2, 4, 6])
def listsubtraction(parent,child):
    answer=[]
    for element in parent:
        if element not in child:
            answer.append(element)
    return answer

我认为这应该可行。我是初学者,所以请原谅我的错误

我们也可以使用set方法来查找两个列表之间的差异

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
y = [1, 3, 5, 7, 9]
list(set(x).difference(y))
[0, 2, 4, 6, 8]

Let:

>>> xs = [1, 2, 3, 4, 3, 2, 1]
>>> ys = [1, 3, 3]  

每一项只保留一次xs - ys == {2,4}

取集合差值:

>>> set(xs) - set(ys)
{2, 4}

删除所有xs - ys == [2,4,2]

>>> [x for x in xs if x not in ys]
[2, 4, 2]

如果ys很大,为了获得更好的性能,只将1个ys转换为一个set:

>>> ys_set = set(ys)
>>> [x for x in xs if x not in ys_set]
[2, 4, 2]

只删除相同数量的出现xs - ys == [2,4,2,1]

from collections import Counter, defaultdict

def diff(xs, ys):
    counter = Counter(ys)
    for x in xs:
        if counter[x] > 0:
            counter[x] -= 1
            continue
        yield x

>>> list(diff(xs, ys))
[2, 4, 2, 1]

1 .将xs转换为set并获取set的差异是不必要的(并且更慢,并且破坏顺序),因为我们只需要在xs上迭代一次。

如果列表允许重复元素,你可以使用Counter from collections:

from collections import Counter
result = list((Counter(x)-Counter(y)).elements())

如果你需要保留x中元素的顺序:

result = [ v for c in [Counter(y)] for v in x if not c[v] or c.subtract([v]) ]