我想取列表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和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]
当前回答
list1 = ['a', 'c', 'a', 'b', 'k']
list2 = ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'd', 'e', 'f']
for e in list1:
try:
list2.remove(e)
except ValueError:
print(f'{e} not in list')
list2
# ['a', 'a', 'c', 'd', 'e', 'f']
这将改变list2。如果你想保护list2,只需复制它,并在这段代码中使用list2的副本。
其他回答
这个例子减去了两个列表:
# List of pairs of points
list = []
list.append([(602, 336), (624, 365)])
list.append([(635, 336), (654, 365)])
list.append([(642, 342), (648, 358)])
list.append([(644, 344), (646, 356)])
list.append([(653, 337), (671, 365)])
list.append([(728, 13), (739, 32)])
list.append([(756, 59), (767, 79)])
itens_to_remove = []
itens_to_remove.append([(642, 342), (648, 358)])
itens_to_remove.append([(644, 344), (646, 356)])
print("Initial List Size: ", len(list))
for a in itens_to_remove:
for b in list:
if a == b :
list.remove(b)
print("Final List Size: ", len(list))
对于许多用例,您想要的答案是:
ys = set(y)
[item for item in x if item not in ys]
这是aaronasterling的答案和quantumSoup的答案的混合。
Aaronasterling的版本对x中的每个元素进行len(y)项比较,因此需要二次型时间。量子汤的版本使用集合,所以它对x中的每个元素执行一个常量时间集合查找,但是,因为它将x和y都转换为集合,所以它失去了元素的顺序。
通过只将y转换为一个集合,并按顺序迭代x,您可以获得两者的最佳效果——线性时间和有序保存
然而,这仍然存在一个问题:它要求你的元素是可哈希的。这是集合的本质。**如果你试图,例如,从另一个字典列表中减去一个字典列表,但要减去的列表很大,你会怎么做?
如果你能以某种方式装饰你的值使它们是可哈希的,这就解决了问题。例如,对于一个值本身是可哈希的平面字典:
ys = {tuple(item.items()) for item in y}
[item for item in x if tuple(item.items()) not in ys]
如果你的类型有点复杂(例如,你经常处理json兼容的值,它们是可哈希的,或者列表或字典,它们的值递归是相同的类型),你仍然可以使用这个解决方案。但是有些类型就是不能转换成任何可哈希的类型。
如果你的项目不是,也不能是可哈希的,但它们具有可比性,你至少可以通过排序和使用平分得到对数线性时间(O(N*log M),这比列表解的O(N*M)时间好得多,但不如集合解的O(N+M)时间好:
ys = sorted(y)
def bisect_contains(seq, item):
index = bisect.bisect(seq, item)
return index < len(seq) and seq[index] == item
[item for item in x if bisect_contains(ys, item)]
如果你的项目既不是可哈希的也不是可比较的,那么你就只能用二次解了。
*请注意,您也可以通过使用一对OrderedSet对象来实现这一点,您可以为此找到食谱和第三方模块。但我认为这样更简单。
**设置查找是常量时间的原因是,它所要做的就是散列值,并查看是否有该散列的条目。如果它不能散列值,这将不起作用。
使用集合差
>>> z = list(set(x) - set(y))
>>> z
[0, 8, 2, 4, 6]
或者你可以让x和y是集合所以你不需要做任何转换。
试试这个。
def subtract_lists(a, b):
""" Subtracts two lists. Throws ValueError if b contains items not in a """
# Terminate if b is empty, otherwise remove b[0] from a and recurse
return a if len(b) == 0 else [a[:i] + subtract_lists(a[i+1:], b[1:])
for i in [a.index(b[0])]][0]
>>> x = [1,2,3,4,5,6,7,8,9,0]
>>> y = [1,3,5,7,9]
>>> subtract_lists(x,y)
[2, 4, 6, 8, 0]
>>> x = [1,2,3,4,5,6,7,8,9,0,9]
>>> subtract_lists(x,y)
[2, 4, 6, 8, 0, 9] #9 is only deleted once
>>>
使用一个列表推导式来计算差值,同时保持x的原始顺序:
[item for item in x if item not in y]
如果你不需要列表属性(例如,排序),使用一个集差异,正如其他答案所建议的:
list(set(x) - set(y))
为了允许x - y中缀语法,在从list继承的类上重写__sub__:
class MyList(list):
def __init__(self, *args):
super(MyList, self).__init__(args)
def __sub__(self, other):
return self.__class__(*[item for item in self if item not in other])
用法:
x = MyList(1, 2, 3, 4)
y = MyList(2, 5, 2)
z = x - y