在python中列出减法

时间:2012-09-26 13:06:26

标签: python python-3.x

  

可能重复:
  Python list subtraction operation

在Python中,你可以像这样连接列表:

print([3,4,5]+[4,5])

给出了这个输出:

[3,4,5,4,5]

但我正在寻找的是一个等效的“减法”操作,所以做这样的事情:

print([3,4,5]-[4,5])

将输出:

[3]

但是,没有为列表定义减法运算符。我试过这个:

a = [3,4,5]
b = [4,5]
print(list(filter(lambda x : x not in b,a)))

哪个有效,但我不确定这是否是最好的方法。我还想保留原始项目位置

7 个答案:

答案 0 :(得分:5)

您可以使用列表理解轻松完成此操作:

nl = [elem for elem in a if elem not in b]

修改

最好使用set进行测试。这将删除列表中的重复项。

bb= set(b)
nl = [elem for elem in a if elem not in bb]

答案 1 :(得分:4)

这是一个定义不明确的问题。我可以想到列表“减法”的几个非等价定义,其中两个已经表示过:截断(通过切片) - 连接的真正反转;和过滤,类似于集合的“减法”(真正的相对互补)的定义。对于过滤,使用a上的列表推导并将b转换为集合是最佳方法。 (即larsvegas的回答。)

但是尚未考虑的一个版本是减法的 multiset 定义。 Python的Counter类型为我们提供了一个多重集:

>>> from collections import Counter
>>> a = [3, 4, 5]
>>> b = [4, 5]
>>> a_counter = Counter(a)
>>> b_counter = Counter(b)
>>> a_counter
Counter({3: 1, 4: 1, 5: 1})
>>> b_counter
Counter({4: 1, 5: 1})
>>> a_counter - b_counter
Counter({3: 1})

当然,这不会保留顺序,但我们可以根据a的结果过滤a_counter - b_counter来解决这个问题:

def subtract_lists(a, b):
    multiset_difference = Counter(a) - Counter(b)
    result = []
    for i in a:
        if i in multiset_difference:
            result.append(i)
            multiset_difference -= Counter((i,))
    return result

这有几个不错的属性。它保留了秩序;它起到连接的真正反转的作用;它在可以包含重复项的数据类型上实现直观一致的减法版本;它在线性时间内工作。

>>> subtract_lists(a, b)
[3]
>>> subtract_lists([1, 2, 3, 4], [2, 3, 4])
[1]
>>> subtract_lists([1, 2, 3, 4], [2, 4])
[1, 3]
>>> subtract_lists([1, 2, 3, 4, 4, 4], [2, 4])
[1, 3, 4, 4]

答案 2 :(得分:2)

a = [3,4,5]
b = [4,5]

list(set(a) -  set(b))
[3]

答案 3 :(得分:2)

如果你的意思是从列表中删除最后一个元素时的减法,那么使用列表切片这是一个非常简单的操作:

def list_subtraction(seq, remove):
    l = len(remove)
    if seq[-l:] == remove:
        return seq[:-l]
    else:
        raise ValueError("Subtraction not possible, "
                         "{} is not a tail of {}.".format(remove, seq))

答案 4 :(得分:1)

这当然是因为它只是附加,这就是为什么重复项不会被删除或受到影响。

减法只是截止结束:

a = [3, 4, 5]
b = [4, 5]
c = a + b

d = c[:-len(b)]

这会使d等于a,即[3, 4, 5]

答案 5 :(得分:1)

假设:

a = [3, 4, 5]
b = [4, 5]

然后,根据您的需要,以下其中一项应该有效。

# remove 'b' from the end of 'a' if it's there (strict de-concatenation)
if a[-len(b):] == b:
    a = a[:-len(b)]

# remove any elements from 'a' that are in `b` (including multiples)
bset = set(b)
a = [x for x in a if x not in bset]

# faster version of above but doesn't preserve order
a = list(set(a) - set(b))

# remove elements from 'a' that are in 'b' (one leftmost item only)
bset = set(b)
a = [x for x in a if x not in bset or bset.remove(x)]

# remove elements from 'a' that are in 'b' (one rightmost item only)
bset = set(b)
a = list(reversed([x for x in reversed(a) if x not in bset or bset.remove(x)]))

答案 6 :(得分:0)

如果您希望从列表中的任何位置删除内容,并且只删除它们在第二个列表中显示的次数(以便sub([1, 2, 3, 3, 4, 4, 5], [3, 4, 5]) == [1, 2, 3, 4]),则需要更加棘手并删除每个元素从您使用它的右侧列表(的副本):

def sub(l, r):
    '''
    Remove all elements in r from l
    '''
    r = r[:]
    res = []
    for a in l:
        try:
            i = r.index(a)
        except ValueError:
            res.append(a)
        else:
            del r[i]
    return res

如果你想要,例如,[1, 2, 3] - [4]是一个错误,你可以在循环后检查r是否为非空。