ใน Python วิธีที่ดีที่สุดในการคำนวณความแตกต่างระหว่างสองรายการคืออะไร
ตัวอย่าง
A = [1,2,3,4]
B = [2,5]
A - B = [1,3,4]
B - A = [5]
ใน Python วิธีที่ดีที่สุดในการคำนวณความแตกต่างระหว่างสองรายการคืออะไร
ตัวอย่าง
A = [1,2,3,4]
B = [2,5]
A - B = [1,3,4]
B - A = [5]
คำตอบ:
ใช้set
ถ้าคุณไม่สนใจเกี่ยวกับการสั่งซื้อหรือการทำซ้ำรายการ ใช้รายการความเข้าใจหากคุณ:
>>> def diff(first, second):
second = set(second)
return [item for item in first if item not in second]
>>> diff(A, B)
[1, 3, 4]
>>> diff(B, A)
[5]
>>>
set
กับ B นั้นไม่เป็นอันตราย แต่นำไปใช้กับA
และใช้ผลลัพธ์แทนแบบดั้งเดิมA
ไม่ใช่
หากคำสั่งซื้อไม่สำคัญคุณสามารถคำนวณความแตกต่างของเซตได้:
>>> set([1,2,3,4]) - set([2,5])
set([1, 4, 3])
>>> set([2,5]) - set([1,2,3,4])
set([5])
คุณสามารถทำ
list(set(A)-set(B))
และ
list(set(B)-set(A))
หนึ่งในสายการบิน:
diff = lambda l1,l2: [x for x in l1 if x not in l2]
diff(A,B)
diff(B,A)
หรือ:
diff = lambda l1,l2: filter(lambda x: x not in l2, l1)
diff(A,B)
diff(B,A)
Python 2.7.3 (ค่าเริ่มต้น 27 ก.พ. 2014, 19:58:35) - IPython 1.1.0 - timeit: (gistub gist)
def diff(a, b):
b = set(b)
return [aa for aa in a if aa not in b]
def set_diff(a, b):
return list(set(a) - set(b))
diff_lamb_hension = lambda l1,l2: [x for x in l1 if x not in l2]
diff_lamb_filter = lambda l1,l2: filter(lambda x: x not in l2, l1)
from difflib import SequenceMatcher
def squeezer(a, b):
squeeze = SequenceMatcher(None, a, b)
return reduce(lambda p,q: p+q, map(
lambda t: squeeze.a[t[1]:t[2]],
filter(lambda x:x[0]!='equal',
squeeze.get_opcodes())))
ผล:
# Small
a = range(10)
b = range(10/2)
timeit[diff(a, b)]
100000 loops, best of 3: 1.97 µs per loop
timeit[set_diff(a, b)]
100000 loops, best of 3: 2.71 µs per loop
timeit[diff_lamb_hension(a, b)]
100000 loops, best of 3: 2.1 µs per loop
timeit[diff_lamb_filter(a, b)]
100000 loops, best of 3: 3.58 µs per loop
timeit[squeezer(a, b)]
10000 loops, best of 3: 36 µs per loop
# Medium
a = range(10**4)
b = range(10**4/2)
timeit[diff(a, b)]
1000 loops, best of 3: 1.17 ms per loop
timeit[set_diff(a, b)]
1000 loops, best of 3: 1.27 ms per loop
timeit[diff_lamb_hension(a, b)]
1 loops, best of 3: 736 ms per loop
timeit[diff_lamb_filter(a, b)]
1 loops, best of 3: 732 ms per loop
timeit[squeezer(a, b)]
100 loops, best of 3: 12.8 ms per loop
# Big
a = xrange(10**7)
b = xrange(10**7/2)
timeit[diff(a, b)]
1 loops, best of 3: 1.74 s per loop
timeit[set_diff(a, b)]
1 loops, best of 3: 2.57 s per loop
timeit[diff_lamb_filter(a, b)]
# too long to wait for
timeit[diff_lamb_filter(a, b)]
# too long to wait for
timeit[diff_lamb_filter(a, b)]
# TypeError: sequence index must be integer, not 'slice'
ฟังก์ชั่นรายการความเข้าใจ @ roman-bodnarchuk def diff (a, b)ดูเหมือนจะเร็วขึ้น
ตัวอย่างข้างต้นทำให้เกิดปัญหาการคำนวณความแตกต่างเล็กน้อย สมมติว่าการเรียงลำดับหรือยกเลิกการทำซ้ำแน่นอนทำให้ง่ายต่อการคำนวณความแตกต่าง แต่ถ้าการเปรียบเทียบของคุณไม่สามารถจัดหาสมมติฐานเหล่านั้นได้คุณจะต้องมีการใช้อัลกอริทึมแบบกระจายเล็กน้อย ดู difflib ในไลบรารี่มาตรฐานของไพ ธ อน
#! /usr/bin/python2
from difflib import SequenceMatcher
A = [1,2,3,4]
B = [2,5]
squeeze=SequenceMatcher( None, A, B )
print "A - B = [%s]"%( reduce( lambda p,q: p+q,
map( lambda t: squeeze.a[t[1]:t[2]],
filter(lambda x:x[0]!='equal',
squeeze.get_opcodes() ) ) ) )
เอาท์พุท:
A - B = [[1, 3, 4]]
print
มีการเปลี่ยนแปลงจากคำสั่งไปยังฟังก์ชั่นและreduce
, filter
และmap
ได้รับการประกาศ unpythonic (และฉันคิดว่าGuido อาจจะถูกต้อง - ฉันไม่เข้าใจreduce
เช่นกัน)
A = [1,2,3,4]
B = [2,5]
#A - B
x = list(set(A) - set(B))
#B - A
y = list(set(B) - set(A))
print x
print y
คุณต้องการที่จะใช้แทนset
list
ในกรณีที่คุณต้องการความแตกต่างที่จะลึกเข้าไปในรายการของคุณซ้ำฉันเขียนแพ็คเกจสำหรับไพ ธ อน: https://github.com/erasmose/deepdiff
ติดตั้งจาก PyPi:
pip install deepdiff
หากคุณเป็น Python3 คุณต้องติดตั้งด้วย:
pip install future six
>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function
วัตถุเดียวกันกลับว่างเปล่า
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> ddiff = DeepDiff(t1, t2)
>>> print (ddiff.changes)
{}
ประเภทของรายการมีการเปลี่ยนแปลง
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> ddiff = DeepDiff(t1, t2)
>>> print (ddiff.changes)
{'type_changes': ["root[2]: 2=<type 'int'> vs. 2=<type 'str'>"]}
มูลค่าของรายการมีการเปลี่ยนแปลง
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> ddiff = DeepDiff(t1, t2)
>>> print (ddiff.changes)
{'values_changed': ['root[2]: 2 ====>> 4']}
รายการที่เพิ่มและ / หรือลบออก
>>> 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.changes)
{'dic_item_added': ['root[5, 6]'],
'dic_item_removed': ['root[4]'],
'values_changed': ['root[2]: 2 ====>> 4']}
ความแตกต่างของสตริง
>>> 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.changes, indent = 2)
{ 'values_changed': [ 'root[2]: 2 ====>> 4',
"root[4]['b']:\n--- \n+++ \n@@ -1 +1 @@\n-world\n+world!"]}
>>>
>>> print (ddiff.changes['values_changed'][1])
root[4]['b']:
---
+++
@@ -1 +1 @@
-world
+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.changes, indent = 2)
{ 'values_changed': [ "root[4]['b']:\n--- \n+++ \n@@ -1,5 +1,4 @@\n-world!\n-Goodbye!\n+world\n 1\n 2\n End"]}
>>>
>>> print (ddiff.changes['values_changed'][0])
root[4]['b']:
---
+++
@@ -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.changes, indent = 2)
{ 'type_changes': [ "root[4]['b']: [1, 2, 3]=<type 'list'> vs. world\n\n\nEnd=<type 'str'>"]}
ความแตกต่างของรายการ
>>> 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, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff.changes, indent = 2)
{ 'list_removed': ["root[4]['b']: [3]"]}
ความแตกต่างของรายการ 2: โปรดทราบว่าไม่คำนึงถึงการสั่งซื้อ
>>> # Note that it DOES NOT take order into account
... 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]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff.changes, indent = 2)
{ }
รายการที่มีพจนานุกรม:
>>> 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.changes, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
'values_changed': ["root[4]['b'][2][1]: 1 ====>> 3"]}
วิธีที่ง่ายที่สุด
ใช้set (). different (set ())
list_a = [1,2,3]
list_b = [2,3]
print set(list_a).difference(set(list_b))
คำตอบคือ set([1])
ในกรณีของรายการพจนานุกรมโซลูชันการทำความเข้าใจรายการแบบสมบูรณ์จะทำงานในขณะที่set
โซลูชันยกขึ้น
TypeError: unhashable type: 'dict'
def diff(a, b):
return [aa for aa in a if aa not in b]
d1 = {"a":1, "b":1}
d2 = {"a":2, "b":2}
d3 = {"a":3, "b":3}
>>> diff([d1, d2, d3], [d2, d3])
[{'a': 1, 'b': 1}]
>>> diff([d1, d2, d3], [d1])
[{'a': 2, 'b': 2}, {'a': 3, 'b': 3}]
รหัสอย่างง่ายที่ให้ความแตกต่างกับสินค้าหลายรายการหากคุณต้องการ:
a=[1,2,3,3,4]
b=[2,4]
tmp = copy.deepcopy(a)
for k in b:
if k in tmp:
tmp.remove(k)
print(tmp)
เมื่อดูที่TimeComplexityของ In-operator ในกรณีที่แย่ที่สุดมันจะทำงานกับ O (n) แม้กระทั่งสำหรับชุด
ดังนั้นเมื่อเปรียบเทียบสองอาร์เรย์เราจะมี TimeComplexity ของ O (n) ในกรณีที่ดีที่สุดและ O (n ^ 2) ในกรณีที่แย่ที่สุด
ทางเลือก (แต่น่าเสียดายที่ซับซ้อนกว่า) ซึ่งทำงานร่วมกับ O (n) ในกรณีที่ดีที่สุดและแย่ที่สุดคืออันนี้:
# Compares the difference of list a and b
# uses a callback function to compare items
def diff(a, b, callback):
a_missing_in_b = []
ai = 0
bi = 0
a = sorted(a, callback)
b = sorted(b, callback)
while (ai < len(a)) and (bi < len(b)):
cmp = callback(a[ai], b[bi])
if cmp < 0:
a_missing_in_b.append(a[ai])
ai += 1
elif cmp > 0:
# Item b is missing in a
bi += 1
else:
# a and b intersecting on this item
ai += 1
bi += 1
# if a and b are not of same length, we need to add the remaining items
for ai in xrange(ai, len(a)):
a_missing_in_b.append(a[ai])
return a_missing_in_b
เช่น
>>> a=[1,2,3]
>>> b=[2,4,6]
>>> diff(a, b, cmp)
[1, 3]
set(b)
เพื่อให้แน่ใจว่าอัลกอริทึมคือ O (nlogn) แทน Theta (n ^ 2)