我在Python中有两个列表:
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']
假设每个列表中的元素都是唯一的,我想用第一个列表中的项创建第三个列表,这些项不在第二个列表中:
temp3 = ['Three', 'Four']
有没有没有周期和检查的快速方法?
我在Python中有两个列表:
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']
假设每个列表中的元素都是唯一的,我想用第一个列表中的项创建第三个列表,这些项不在第二个列表中:
temp3 = ['Three', 'Four']
有没有没有周期和检查的快速方法?
当前回答
以下是@SuperNova的回答的修改版本
def get_diff(a: list, b: list) -> list:
return list(set(a) ^ set(b))
其他回答
我知道这个问题已经得到了很好的答案,但我希望使用numpy添加以下方法。
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']
list(np.setdiff1d(temp1,temp2))
['Four', 'Three'] #Output
下面是@arkolec的回答,下面是一个用于比较列表、元组和集的实用程序类:
from difflib import SequenceMatcher
class ListDiffer:
def __init__(self, left, right, strict:bool=False):
assert isinstance(left, (list, tuple, set)), "left must be list, tuple or set"
assert isinstance(right, (list, tuple, set)), "right must be list, tuple or set"
self.l = list(left) if isinstance(left, (tuple, set)) else left
self.r = list(right) if isinstance(left, (tuple, set)) else right
if strict:
assert isinstance(left, right.__class__), \
f'left type ({left.__class__.__name__}) must equal right type ({right.__class__.__name__})'
self.diffs = []
self.equal = []
for tag, i, j, k, l in SequenceMatcher(None, self.l, self.r).get_opcodes():
if tag in ['delete', 'replace', 'insert']:
self.diffs.append((tag, i, j, k, l))
elif tag == 'equal':
[self.equal.append(v) for v in left[i:j]]
def has_diffs(self):
return len(self.diffs) > 0
def only_left(self):
a = self.l[:]
[a.remove(v) for v in self.equal]
return a
def only_right(self):
a = self.r[:]
[a.remove(v) for v in self.equal]
return a
def __str__(self, verbose:bool=False):
iD = 0
sb = []
if verbose:
sb.append(f"left: {self.l}\n")
sb.append(f"right: {self.r}\n")
sb.append(f"diffs: ")
for tag, i, j, k, l in self.diffs:
s = f"({iD})"
if iD > 0: sb.append(' | ')
if tag in ('delete', 'replace'): s = f'{s} l:{self.l[i:j]}'
if tag in ('insert', 'replace'): s = f'{s} r:{self.r[k:l]}'
sb.append(s)
iD = iD + 1
if verbose:
sb.append(f"\nequal: {self.equal}")
return ''.join(sb)
def __repr__(self) -> str:
return "<ListDiffer> {}".format(self.__str__())
用法:
left = ['a','b','c']
right = ['aa','b','c','d']
# right = ('aa','b','c','d')
ld = ListDiffer(left, right, strict=True)
print(f'ld.has_diffs(): {ld.has_diffs()}')
print(f'ld: {ld}')
print(f'ld.only_left(): {ld.only_left()}')
print(f'ld.only_right(): {ld.only_right()}')
输出:
ld.has_diffs(): True
ld: (0) l:['a'] r:['aa'] | (1) r:['d']
ld.only_left(): ['a']
ld.only_right(): ['aa', 'd']
我不能说性能,但你可以使用ld.only_left()来获得你正在寻找的结果。
可以使用python的XOR运算符来完成。
这将删除每个列表中的重复项 这将显示temp1与temp2和temp2与temp1的差异。
set(temp1) ^ set(temp2)
这可能比马克的清单理解还要快:
list(itertools.filterfalse(set(temp2).__contains__, temp1))
这里有一些简单的、保持顺序的方法来区分两个字符串列表。
Code
使用pathlib的一个不寻常的方法:
import pathlib
temp1 = ["One", "Two", "Three", "Four"]
temp2 = ["One", "Two"]
p = pathlib.Path(*temp1)
r = p.relative_to(*temp2)
list(r.parts)
# ['Three', 'Four']
这假设两个列表包含相同开头的字符串。更多细节请参阅文档。注意,与set操作相比,它不是特别快。
使用itertools.zip_longest的直接实现:
import itertools as it
[x for x, y in it.zip_longest(temp1, temp2) if x != y]
# ['Three', 'Four']