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']
2nd has [5, 4, 3, 2]
both have [1]
1st has [2, 3, 4, 5]
3
可以使用以下简单函数找到两个列表(例如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)
#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))
就像其他非元组在这个方向上产生答案一样,它保留了秩序
2
现有的解决方案都提供以下一种或另一种:
比O(n * m)性能快 .
保留输入列表的顺序 .
但到目前为止,没有任何解决方案 . 如果你想要两者,试试这个:
s = set(temp2)
temp3 = [x for x in temp1 if x not in s]
Performance test
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
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])
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
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
12
temp3 = [item for item in temp1 if item not in temp2]
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"
-1
In [5]: list(set(temp1) - set(temp2))
Out[5]: ['Four', 'Three']
要小心
In [5]: set([1, 2]) - set([2, 3])
Out[5]: set([1])
25 回答
如果您想以递归方式获得差异,我已经为python编写了一个包:https://github.com/seperman/deepdiff
安装
从PyPi安装:
示例用法
输入
同一对象返回空
项目类型已更改
商品的 Value 已经改变
添加和/或删除项目
字符串差异
字符串差异2
输入更改
列表差异
清单差异2:
列出差异忽略顺序或重复:(使用与上面相同的词典)
包含字典的列表:
集:
命名元组:
自定义对象:
添加了对象属性:
我想要一些需要两个列表的东西,并且可以在
bash
中执行diff
. 由于当您搜索"python diff two lists"并且不是非常具体时会首先弹出此问题,我将发布我想出的内容 .使用
difflib
中的SequenceMather,您可以比较两个列表,如diff
. 其他答案都没有告诉你差异发生的位置,但这个答案会发生 . 有些答案只能在一个方向上产生差异 . 有些人重新排序元素 . 有些人不处理重复 . 但是这个解决方案为您提供了两个列表的真正区别:这输出:
当然,如果您的应用程序做出与其他答案相同的假设,您将从中受益最多 . 但如果您正在寻找真正的
diff
功能,那么这是唯一的出路 .例如,其他答案都无法处理:
但是这个做了:
可以使用以下简单函数找到两个列表(例如list1和list2)之间的差异 .
要么
通过使用上述函数,可以使用
diff(temp2, temp1)
或diff(temp1, temp2)
找到差异 . 两者都会给出结果['Four', 'Three']
. 您不必担心列表的顺序或首先给出哪个列表 .Python doc reference
对于最简单的情况,这是一个
Counter
答案 .这比执行双向差异的那个要短,因为它只能完成问题所要求的:生成第一个列表中的内容而不是第二个列表中的内容 .
或者,根据您的可读性偏好,它可以提供一个像样的单行:
输出:
请注意,如果您只是迭代它,则可以删除
list(...)
调用 .因为此解决方案使用计数器,所以它与许多基于集合的答案相比正确处理数量 . 例如,在此输入上:
输出是:
如果你真的在研究性能,那么使用numpy!
这是完整的笔记本作为github上的要点,列表,numpy和pandas之间的比较 .
https://gist.github.com/denfromufa/2821ff59b02e9482be15d27f2bbd4451
这可以用一行解决 . 问题是两个列表(temp1和temp2)在第三个列表(temp3)中返回它们的差异 .
因为现有的解决方案都没有产生元组,所以我会抛弃:
或者:
就像其他非元组在这个方向上产生答案一样,它保留了秩序
现有的解决方案都提供以下一种或另一种:
比O(n * m)性能快 .
保留输入列表的顺序 .
但到目前为止,没有任何解决方案 . 如果你想要两者,试试这个:
Performance test
结果:
我提出的方法以及保持顺序也(稍微)比set减法更快,因为它不需要构造不必要的集合 . 如果第一个列表比第二个列表长得多并且散列是昂贵的,则性能差异会更明显 . 这是第二次测试,证明了这一点:
结果:
这是区分两个列表(无论内容是什么)的简单方法,您可以得到如下所示的结果:
希望这会有所帮助 .
我在游戏中为此已经太晚了,但你可以对上面提到的一些代码的性能进行比较,两个最快的竞争者是,
我为编码的基本级别道歉 .
可以使用python XOR运算符完成 .
这将删除每个列表中的重复项
这将显示temp1与temp1和temp2与temp1的区别 .
单行版 arulmr 解决方案
这是另一种解决方案:
假设我们有两个列表
我们可以从上面的两个列表中看到,项目1,3,5存在于list2中,而项目7,9则不存在 . 上另一方面,项目1,3,5存在于list1中,而项目2,4则不存在 .
返回包含项目7,9和2,4的新列表的最佳解决方案是什么?
上面的所有答案都找到了解决方案,现在最优化的是什么?
与
使用timeit我们可以看到结果
回报
试试这个:
如果difflist的元素已排序并设置,则可以使用naive方法 .
或使用本机设置方法:
天真的解决方案:0.0787101593292
原生集解决方案:0.998837615564
如果您遇到
TypeError: unhashable type: 'list'
,则需要将列表或集合转换为元组,例如另见How to compare a list of lists/sets in python?
我们可以计算交集减去联合列表:
这可能比马克的列表理解速度更快:
以下是一些简单的方法来区分两个字符串列表 .
Code
使用pathlib的一种不寻常的方法:
这假设两个列表都包含具有等效开头的字符串 . 有关详细信息,请参阅docs . 注意,与设置操作相比,它不是特别快 .
使用itertools.zip_longest的直接实现:
最简单的方法,
使用 set().difference(set())
答案是
set([1])
可以打印为列表,
如果你想要更像变更集的东西......可以使用Counter
要小心
您可能期望/希望它等于
set([1, 3])
. 如果您确实想要set([1, 3])
作为答案,则需要使用set([1, 2]).symmetric_difference(set([2, 3]))
.