我在 Python 中有两个列表,如下所示:
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']
我需要创建第三个列表,其中包含第二个列表中不存在的第一个列表中的项目。从我必须得到的例子中
temp3 = ['Three', 'Four']
有没有没有循环和检查的快速方法?
我在 Python 中有两个列表,如下所示:
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']
我需要创建第三个列表,其中包含第二个列表中不存在的第一个列表中的项目。从我必须得到的例子中
temp3 = ['Three', 'Four']
有没有没有循环和检查的快速方法?
temp1
要获取 in但不在 in 的元素temp2
:
In [5]: list(set(temp1) - set(temp2))
Out[5]: ['Four', 'Three']
注意它是不对称的:
In [5]: set([1, 2]) - set([2, 3])
Out[5]: set([1])
您可能期望/希望它等于set([1, 3])
. 如果您确实想要set([1, 3])
作为您的答案,您可以使用set([1, 2]).symmetric_difference(set([2, 3]))
.
现有的解决方案都提供以下一种或另一种:
但到目前为止,还没有解决方案两者兼而有之。如果你想要两者,试试这个:
s = set(temp2)
temp3 = [x for x in temp1 if x not in s]
性能测试
import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print timeit.timeit('list(set(temp1) - set(temp2))', init, number = 100000)
print timeit.timeit('s = set(temp2);[x for x in temp1 if x not in s]', init, number = 100000)
print timeit.timeit('[item for item in temp1 if item not in temp2]', init, number = 100000)
结果:
4.34620224079 # ars' answer
4.2770634955 # This answer
30.7715615392 # matt b's answer
我提出的方法以及保留顺序也(略)比集合减法快,因为它不需要构造不必要的集合。如果第一个列表比第二个列表长得多并且散列很昂贵,则性能差异会更加明显。这是证明这一点的第二个测试:
init = '''
temp1 = [str(i) for i in range(100000)]
temp2 = [str(i * 2) for i in range(50)]
'''
结果:
11.3836875916 # ars' answer
3.63890368748 # this answer (3 times faster!)
37.7445402279 # matt b's answer
可以使用 python XOR 运算符来完成。
set(temp1) ^ set(temp2)
temp3 = [item for item in temp1 if item not in temp2]
可以使用以下简单函数找到两个列表(例如 list1 和 list2)之间的区别。
def diff(list1, list2):
c = set(list1).union(set(list2)) # or c = set(list1) | set(list2)
d = set(list1).intersection(set(list2)) # or d = set(list1) & set(list2)
return list(c - d)
或者
def diff(list1, list2):
return list(set(list1).symmetric_difference(set(list2))) # or return list(set(list1) ^ set(list2))
通过使用上述功能,可以使用diff(temp2, temp1)
或找到差异diff(temp1, temp2)
。两者都会给出结果['Four', 'Three']
。您不必担心列表的顺序或首先给出哪个列表。
如果您想要递归地进行差异,我已经为 python 编写了一个包: https ://github.com/seperman/deepdiff
从 PyPi 安装:
pip install deepdiff
输入
>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function # In case running on Python 2
相同的对象返回空
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> print(DeepDiff(t1, t2))
{}
项目类型已更改
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{ 'type_changes': { 'root[2]': { 'newtype': <class 'str'>,
'newvalue': '2',
'oldtype': <class 'int'>,
'oldvalue': 2}}}
物品的价值发生了变化
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}
添加和/或删除的项目
>>> t1 = {1:1, 2:2, 3:3, 4:4}
>>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff)
{'dic_item_added': ['root[5]', 'root[6]'],
'dic_item_removed': ['root[4]'],
'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}
字符串差异
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
>>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
"root[4]['b']": { 'newvalue': 'world!',
'oldvalue': 'world'}}}
字符串差异 2
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
'+++ \n'
'@@ -1,5 +1,4 @@\n'
'-world!\n'
'-Goodbye!\n'
'+world\n'
' 1\n'
' 2\n'
' End',
'newvalue': 'world\n1\n2\nEnd',
'oldvalue': 'world!\n'
'Goodbye!\n'
'1\n'
'2\n'
'End'}}}
>>>
>>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
---
+++
@@ -1,5 +1,4 @@
-world!
-Goodbye!
+world
1
2
End
类型更改
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'type_changes': { "root[4]['b']": { 'newtype': <class 'str'>,
'newvalue': 'world\n\n\nEnd',
'oldtype': <class 'list'>,
'oldvalue': [1, 2, 3]}}}
列出差异
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}
列出差异2:
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'iterable_item_added': {"root[4]['b'][3]": 3},
'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
"root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}
列出差异忽略顺序或重复:(使用与上述相同的字典)
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2, ignore_order=True)
>>> print (ddiff)
{}
包含字典的列表:
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}
套:
>>> t1 = {1, 2, 8}
>>> t2 = {1, 2, 3, 5}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (DeepDiff(t1, t2))
{'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}
命名元组:
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> t1 = Point(x=11, y=22)
>>> t2 = Point(x=11, y=23)
>>> pprint (DeepDiff(t1, t2))
{'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}
自定义对象:
>>> class ClassA(object):
... a = 1
... def __init__(self, b):
... self.b = b
...
>>> t1 = ClassA(1)
>>> t2 = ClassA(2)
>>>
>>> pprint(DeepDiff(t1, t2))
{'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
添加了对象属性:
>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
最简单的方法,
使用set().difference(set())
list_a = [1,2,3]
list_b = [2,3]
print set(list_a).difference(set(list_b))
答案是set([1])
可以打印为列表,
print list(set(list_a).difference(set(list_b)))
试试这个:
temp3 = set(temp1) - set(temp2)
如果您真的在研究性能,请使用 numpy!
这是 github 上的完整笔记本,其中包含 list、numpy 和 pandas 之间的比较。
https://gist.github.com/denfromufa/2821ff59b02e9482be15d27f2bbd4451
我会折腾,因为目前的解决方案都没有产生元组:
temp3 = tuple(set(temp1) - set(temp2))
或者:
#edited using @Mark Byers idea. If you accept this one as answer, just accept his instead.
temp3 = tuple(x for x in temp1 if x not in set(temp2))
像这个方向的其他非元组产生答案一样,它保持顺序
我想要一个需要两个列表并且可以做diff
in 的东西bash
。由于当您搜索“python diff two lists”时首先弹出此问题并且不是很具体,所以我将发布我想出的内容。
使用SequenceMather
fromdifflib
你可以像一样比较两个列表diff
。其他答案都不会告诉您差异发生的位置,但这个答案可以。一些答案仅在一个方向上给出了差异。一些重新排序元素。有些不处理重复项。但是这个解决方案让你在两个列表之间有一个真正的区别:
a = 'A quick fox jumps the lazy dog'.split()
b = 'A quick brown mouse jumps over the dog'.split()
from difflib import SequenceMatcher
for tag, i, j, k, l in SequenceMatcher(None, a, b).get_opcodes():
if tag == 'equal': print('both have', a[i:j])
if tag in ('delete', 'replace'): print(' 1st has', a[i:j])
if tag in ('insert', 'replace'): print(' 2nd has', b[k:l])
这输出:
both have ['A', 'quick']
1st has ['fox']
2nd has ['brown', 'mouse']
both have ['jumps']
2nd has ['over']
both have ['the']
1st has ['lazy']
both have ['dog']
当然,如果您的应用程序做出与其他答案相同的假设,您将从中受益最多。但是,如果您正在寻找真正的diff
功能,那么这是唯一的方法。
例如,没有其他答案可以处理:
a = [1,2,3,4,5]
b = [5,4,3,2,1]
但是这个可以:
2nd has [5, 4, 3, 2]
both have [1]
1st has [2, 3, 4, 5]
这可能比 Mark 的列表理解还要快:
list(itertools.filterfalse(set(temp2).__contains__, temp1))
这是Counter
最简单情况的答案。
这比上面的双向差异要短,因为它只执行问题要求的内容:生成第一个列表中的内容而不是第二个列表中的内容的列表。
from collections import Counter
lst1 = ['One', 'Two', 'Three', 'Four']
lst2 = ['One', 'Two']
c1 = Counter(lst1)
c2 = Counter(lst2)
diff = list((c1 - c2).elements())
或者,根据您的可读性偏好,它会成为一个不错的单行:
diff = list((Counter(lst1) - Counter(lst2)).elements())
输出:
['Three', 'Four']
请注意,list(...)
如果您只是对其进行迭代,则可以删除该调用。
由于此解决方案使用计数器,因此与许多基于集合的答案相比,它可以正确处理数量。例如在这个输入上:
lst1 = ['One', 'Two', 'Two', 'Two', 'Three', 'Three', 'Four']
lst2 = ['One', 'Two']
输出是:
['Two', 'Two', 'Three', 'Three', 'Four']
这里有一些简单的、保留顺序的方法来区分两个字符串列表。
代码
一种不寻常的方法,使用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']
这假设两个列表都包含具有相同开头的字符串。有关更多详细信息,请参阅文档。请注意,与集合操作相比,它并不是特别快。
一个直接的实现,使用itertools.zip_longest
:
import itertools as it
[x for x, y in it.zip_longest(temp1, temp2) if x != y]
# ['Three', 'Four']
这是另一种解决方案:
def diff(a, b):
xa = [i for i in set(a) if i not in b]
xb = [i for i in set(b) if i not in a]
return xa + xb
如果对 difflist 的元素进行排序和设置,则可以使用简单的方法。
list1=[1,2,3,4,5]
list2=[1,2,3]
print list1[len(list2):]
或使用本机设置方法:
subset=set(list1).difference(list2)
print subset
import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print "Naive solution: ", timeit.timeit('temp1[len(temp2):]', init, number = 100000)
print "Native set solution: ", timeit.timeit('set(temp1).difference(temp2)', init, number = 100000)
天真的解决方案:0.0787101593292
原生集解决方案:0.998837615564
我在游戏中为时已晚,但是您可以将上述一些代码的性能与此进行比较,两个最快的竞争者是,
list(set(x).symmetric_difference(set(y)))
list(set(x) ^ set(y))
我为初级编码表示歉意。
import time
import random
from itertools import filterfalse
# 1 - performance (time taken)
# 2 - correctness (answer - 1,4,5,6)
# set performance
performance = 1
numberoftests = 7
def answer(x,y,z):
if z == 0:
start = time.clock()
lists = (str(list(set(x)-set(y))+list(set(y)-set(y))))
times = ("1 = " + str(time.clock() - start))
return (lists,times)
elif z == 1:
start = time.clock()
lists = (str(list(set(x).symmetric_difference(set(y)))))
times = ("2 = " + str(time.clock() - start))
return (lists,times)
elif z == 2:
start = time.clock()
lists = (str(list(set(x) ^ set(y))))
times = ("3 = " + str(time.clock() - start))
return (lists,times)
elif z == 3:
start = time.clock()
lists = (filterfalse(set(y).__contains__, x))
times = ("4 = " + str(time.clock() - start))
return (lists,times)
elif z == 4:
start = time.clock()
lists = (tuple(set(x) - set(y)))
times = ("5 = " + str(time.clock() - start))
return (lists,times)
elif z == 5:
start = time.clock()
lists = ([tt for tt in x if tt not in y])
times = ("6 = " + str(time.clock() - start))
return (lists,times)
else:
start = time.clock()
Xarray = [iDa for iDa in x if iDa not in y]
Yarray = [iDb for iDb in y if iDb not in x]
lists = (str(Xarray + Yarray))
times = ("7 = " + str(time.clock() - start))
return (lists,times)
n = numberoftests
if performance == 2:
a = [1,2,3,4,5]
b = [3,2,6]
for c in range(0,n):
d = answer(a,b,c)
print(d[0])
elif performance == 1:
for tests in range(0,10):
print("Test Number" + str(tests + 1))
a = random.sample(range(1, 900000), 9999)
b = random.sample(range(1, 900000), 9999)
for c in range(0,n):
#if c not in (1,4,5,6):
d = answer(a,b,c)
print(d[1])
这是@SuperNova答案的修改版本
def get_diff(a: list, b: list) -> list:
return list(set(a) ^ set(b))
如果您遇到TypeError: unhashable type: 'list'
您需要将列表或集合转换为元组,例如
set(map(tuple, list_of_lists1)).symmetric_difference(set(map(tuple, list_of_lists2)))
假设我们有两个列表
list1 = [1, 3, 5, 7, 9]
list2 = [1, 2, 3, 4, 5]
从上面的两个列表可以看出,list2中存在1、3、5项,而7、9项不存在。另一方面,项目 1、3、5 存在于 list1 中,而项目 2、4 不存在。
返回包含项目 7、9 和 2、4 的新列表的最佳解决方案是什么?
上面的所有答案都找到了解决方案,现在什么是最优化的?
def difference(list1, list2):
new_list = []
for i in list1:
if i not in list2:
new_list.append(i)
for j in list2:
if j not in list1:
new_list.append(j)
return new_list
相对
def sym_diff(list1, list2):
return list(set(list1).symmetric_difference(set(list2)))
使用 timeit 我们可以看到结果
t1 = timeit.Timer("difference(list1, list2)", "from __main__ import difference,
list1, list2")
t2 = timeit.Timer("sym_diff(list1, list2)", "from __main__ import sym_diff,
list1, list2")
print('Using two for loops', t1.timeit(number=100000), 'Milliseconds')
print('Using two for loops', t2.timeit(number=100000), 'Milliseconds')
返回
[7, 9, 2, 4]
Using two for loops 0.11572412995155901 Milliseconds
Using symmetric_difference 0.11285737506113946 Milliseconds
Process finished with exit code 0
如果您想要更像变更集的东西...可以使用 Counter
from collections import Counter
def diff(a, b):
""" more verbose than needs to be, for clarity """
ca, cb = Counter(a), Counter(b)
to_add = cb - ca
to_remove = ca - cb
changes = Counter(to_add)
changes.subtract(to_remove)
return changes
lista = ['one', 'three', 'four', 'four', 'one']
listb = ['one', 'two', 'three']
In [127]: diff(lista, listb)
Out[127]: Counter({'two': 1, 'one': -1, 'four': -2})
# in order to go from lista to list b, you need to add a "two", remove a "one", and remove two "four"s
In [128]: diff(listb, lista)
Out[128]: Counter({'four': 2, 'one': 1, 'two': -1})
# in order to go from listb to lista, you must add two "four"s, add a "one", and remove a "two"
我们可以计算交集减去列表的并集:
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two', 'Five']
set(temp1+temp2)-(set(temp1)&set(temp2))
Out: set(['Four', 'Five', 'Three'])
我更喜欢使用转换为集合,然后使用“difference()”函数。完整的代码是:
temp1 = ['One', 'Two', 'Three', 'Four' ]
temp2 = ['One', 'Two']
set1 = set(temp1)
set2 = set(temp2)
set3 = set1.difference(set2)
temp3 = list(set3)
print(temp3)
输出:
>>>print(temp3)
['Three', 'Four']
这是最容易理解的,而且如果您在未来处理大数据,如果不需要重复,将其转换为集合将删除重复。希望能帮助到你 ;-)
arulmr解决方案的单行版本
def diff(listA, listB):
return set(listA) - set(listB) | set(listA) -set(listB)
这可以用一行来解决。问题给出了两个列表(temp1 和 temp2),它们在第三个列表(temp3)中返回它们的差异。
temp3 = list(set(temp1).difference(set(temp2)))
我知道这个问题已经得到了很好的答案,但我希望使用numpy
.
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']
list(np.setdiff1d(temp1,temp2))
['Four', 'Three'] #Output
如果您应该从列表a中删除所有值,这些值存在于列表b中。
def list_diff(a, b):
r = []
for i in a:
if i not in b:
r.append(i)
return r
list_diff([1,2,2], [1])
结果:[2,2]
或者
def list_diff(a, b):
return [x for x in a if x not in b]
这是区分两个列表的简单方法(无论内容是什么),您可以得到如下所示的结果:
>>> from sets import Set
>>>
>>> l1 = ['xvda', False, 'xvdbb', 12, 'xvdbc']
>>> l2 = ['xvda', 'xvdbb', 'xvdbc', 'xvdbd', None]
>>>
>>> Set(l1).symmetric_difference(Set(l2))
Set([False, 'xvdbd', None, 12])
希望这会有所帮助。
您可以循环浏览第一个列表,对于不在第二个列表中但在第一个列表中的每个项目,将其添加到第三个列表中。例如:
temp3 = []
for i in temp1:
if i not in temp2:
temp3.append(i)
print(temp3)
def diffList(list1, list2): # returns the difference between two lists.
if len(list1) > len(list2):
return (list(set(list1) - set(list2)))
else:
return (list(set(list2) - set(list1)))
例如,如果list1 = [10, 15, 20, 25, 30, 35, 40]
然后list2 = [25, 40, 35]
返回的列表将是output = [10, 20, 30, 15]
在@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()
来获得你正在寻找的结果。