在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)))
哪个有效,但我不确定这是否是最好的方法。我还想保留原始项目位置
答案 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
是否为非空。