รับความแตกต่างระหว่างสองรายการ


810

ฉันมีสองรายการใน Python ดังนี้:

temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']

ฉันต้องการสร้างรายการที่สามด้วยรายการจากรายการแรกที่ไม่มีอยู่ในรายการที่สอง จากตัวอย่างฉันต้องได้รับ:

temp3 = ['Three', 'Four']

มีวิธีใดที่รวดเร็วโดยไม่มีวงจรและการตรวจสอบหรือไม่?


14
องค์ประกอบมีการรับประกันที่ไม่ซ้ำกัน? หากคุณมีtemp1 = ['One', 'One', 'One']และtemp2 = ['One']คุณต้องการ['One', 'One']กลับมาหรือ[]ไม่?
Michael Mrozek

@ michael-mrozek พวกเขามีเอกลักษณ์
Max Frai

12
คุณต้องการที่จะรักษาลำดับขององค์ประกอบหรือไม่?
Mark Byers

คำตอบ:


1208
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]))


27
@Drewdin: รายการไม่รองรับตัวถูกดำเนินการ "-" อย่างไรก็ตามกำหนดให้ทำและสิ่งที่แสดงให้เห็นข้างต้นหากคุณมองอย่างใกล้ชิด
Godsmith

1
ขอบคุณฉันลงเอยด้วย set (ListA) .symmetric_difference (ListB)
Drewdin

43
ความแตกต่างสมมาตรสามารถเขียนได้ด้วย: ^ (set1 ^ set2)
Bastian

10
กรุณาคุณสามารถแก้ไขคำตอบของคุณและชี้ให้เห็นว่านี่จะคืนค่า temp1-temp2 เท่านั้นหรือไม่ .. อย่างที่คนอื่นพูดเพื่อที่จะคืนความแตกต่างคุณต้องใช้ความแตกต่าง sysmetric: list (set (temp1) ^ set (temp2))
rkachach

ทำไมฉันถึงได้TypeError: 'str' object is not callableเมื่อฉันทำการดำเนินการในวันที่a = [1,2,2,2,3]และb = [2]
d8aninja

476

โซลูชันที่มีอยู่ทั้งหมดเสนออย่างใดอย่างหนึ่งหรืออื่น ๆ ของ:

  • เร็วกว่าประสิทธิภาพ O (n * m)
  • รักษาลำดับของรายการอินพุต

แต่จนถึงขณะนี้ยังไม่มีวิธีแก้ปัญหาทั้งสองอย่าง หากคุณต้องการทั้งคู่ลองสิ่งนี้:

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

2
การสนับสนุนเพิ่มเติมสำหรับคำตอบนี้: วิ่งข้ามกรณีการใช้งานซึ่งการรักษาลำดับของรายการเป็นสิ่งสำคัญสำหรับประสิทธิภาพ เมื่อทำงานกับวัตถุ tarinfo หรือ zipinfo ฉันใช้การลบชุด หากต้องการแยกวัตถุ tarinfo บางอย่างออกจากการแยกออกจากไฟล์เก็บถาวร การสร้างรายการใหม่นั้นเร็วมาก แต่ช้ามากในระหว่างการแตกไฟล์ เหตุผลที่ทำให้ฉันในตอนแรก เปลี่ยนการจัดลำดับรายการวัตถุ tarinfo ใหม่ทำให้เกิดการปรับประสิทธิภาพสูง การสลับไปยังวิธีการเข้าใจรายการบันทึกวัน
Ray Thompson

@ MarkByers - บางทีฉันควรจะเขียนคำถามใหม่ทั้งหมดสำหรับเรื่องนี้ แต่วิธีนี้จะทำงานใน forloop ได้อย่างไร ตัวอย่างเช่นถ้า temp1 และ temp2 ของฉันเปลี่ยนไปเรื่อย ๆ .. และฉันต้องการผนวกข้อมูลใหม่ไปยัง temp3 หรือไม่
Ason

@ MarkByers - ฟังดูดี ฉันจะคิดเกี่ยวกับมันสักหน่อย แต่ +1 สำหรับทางออกที่ยอดเยี่ยม
Ason

ฉันเห็นด้วยกับ @Dejel >>> temp1 = ['หนึ่ง', 'สอง', 'สาม', 'สี่'] >>> temp2 = ['หนึ่ง', 'สอง', 'หก'] >>> s = set (temp2) >>> temp3 = [x สำหรับ x ใน temp1 if x not in s] >>> temp3 ['Three', 'Four']
earlonrails

3
@haccks เนื่องจากการตรวจสอบความเป็นสมาชิกของรายการเป็นการดำเนินการ O (n) (วนซ้ำทั้งรายการ) แต่การตรวจสอบความเป็นสมาชิกของชุดคือ O (1)
Mark Byers

86
temp3 = [item for item in temp1 if item not in temp2]

15
เปลี่ยนtemp2เป็นชุดก่อนจะทำให้ประสิทธิภาพเพิ่มขึ้นเล็กน้อย
Lunaryorn

3
ทรูมันนี่ขึ้นอยู่กับว่า Ockonal ใส่ใจเกี่ยวกับรายการที่ซ้ำกันหรือไม่ (คำถามเดิมไม่ได้พูด)
ด้านข

2
ความคิดเห็นกล่าวว่า (รายการ | tuples) ไม่มีการซ้ำซ้อน

1
ฉัน upvote คำตอบของคุณเพราะฉันคิดว่าคุณพูดถูกในตอนแรก แต่item not in temp2และมักจะกลับผลลัพธ์เดียวกันโดยไม่คำนึงถึงถ้ามีซ้ำกันหรือไม่ได้อยู่ในitem not in set(temp2) temp2
arekolek

5
โหวตมากขึ้นเพราะไม่ต้องการให้รายการในรายการนั้นแฮช
เบรนต์

23

ความแตกต่างระหว่างสองรายการ (พูด 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


7
ทำไมไม่ตั้งค่า (list1) .symmetric_difference (set (list2))
swietyy

20

ในกรณีที่คุณต้องการความแตกต่างซ้ำฉันเขียนแพคเกจสำหรับหลาม: 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]']}

Tuples ที่มีชื่อ:

>>> 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}}}

20

สามารถทำได้โดยใช้ตัวดำเนินการ python XOR

  • นี่จะเป็นการลบรายการที่ซ้ำกันในแต่ละรายการ
  • สิ่งนี้จะแสดงความแตกต่างของ temp1 จาก temp2 และ temp2 จาก temp1

set(temp1) ^ set(temp2)

ทำงานได้ แต่ทำไม
ZakS

คำตอบที่ดีที่สุด!
Artsiom Praneuski

คำตอบคืออะไร! ไพ ธ อนดังนั้น น่าอัศจรรย์
toing_toing

18

วิธีที่ง่ายที่สุด

ใช้set (). different (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)))

14

หากคุณกำลังมองหาประสิทธิภาพจริงๆให้ใช้จำนวนมาก!

นี่คือสมุดบันทึกเต็มรูปแบบเป็นส่วนสำคัญใน GitHub กับการเปรียบเทียบระหว่างรายการ, จำนวนและแพนด้า

https://gist.github.com/denfromufa/2821ff59b02e9482be15d27f2bbd4451

ป้อนคำอธิบายรูปภาพที่นี่


ฉันอัปเดตสมุดบันทึกในลิงค์และภาพหน้าจอ แพนด้าที่น่าแปลกใจช้ากว่าที่สังเกตได้แม้ว่าจะเปลี่ยนไปใช้แฮชโต๊ะภายใน ส่วนหนึ่งอาจเป็นเพราะ upcasting เป็น int64
denfromufa

13

ฉันจะโยนเข้าเนื่องจากไม่มีวิธีแก้ไขปัญหาใดที่ให้ผลลัพธ์เป็น tuple:

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))

เช่นเดียวกับคนอื่น ๆ ที่ไม่ใช่ tuple ให้คำตอบในทิศทางนี้มันจะรักษาความสงบเรียบร้อย


11

ฉันต้องการสิ่งที่จะใช้สองรายการและสามารถทำdiffในสิ่งที่bashทำ เนื่องจากคำถามนี้จะปรากฏขึ้นก่อนเมื่อคุณค้นหา "python diff สองรายการ" และไม่เจาะจงมากฉันจะโพสต์สิ่งที่ฉันคิดไว้

การใช้SequenceMatherจากdifflibคุณสามารถเปรียบเทียบสองรายการเช่น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]


10

สิ่งนี้อาจเร็วกว่าความเข้าใจในรายการของมาร์ค:

list(itertools.filterfalse(set(temp2).__contains__, temp1))

7
อาจต้องการรวมfrom itertools import filterfalseบิตที่นี่ โปรดทราบว่านี่จะไม่ส่งคืนลำดับเช่นเดียวกับรายการอื่น แต่ส่งคืนตัววนซ้ำ
แมตต์ Luongo

7

นี่คือ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']

5

คุณสามารถใช้วิธีการไร้เดียงสาหากองค์ประกอบของ 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


5

ฉันยังสายเกินไปสำหรับเกมนี้ แต่คุณสามารถเปรียบเทียบประสิทธิภาพของโค้ดที่กล่าวถึงข้างต้นกับสิ่งนี้ได้สองสิ่งที่เร็วที่สุดคือ

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])

5

ต่อไปนี้เป็นวิธีรักษาที่เรียบง่ายของการแยกสตริงสองรายการ

รหัส

วิธีการที่ผิดปกติโดยใช้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']

1
โซลูชัน itertools ใช้งานได้เฉพาะเมื่อองค์ประกอบในtemp1และtemp2เข้ากันได้ดี ตัวอย่างเช่นถ้าคุณหันไปรอบ ๆ องค์ประกอบในtemp2หรือแทรกค่าอื่น ๆ ในตอนต้นของtemp2listcomp เพียงแค่จะคืนองค์ประกอบเดียวกันเช่นในtemp1
KenHBS

ใช่มันเป็นคุณสมบัติของวิธีการเหล่านี้ ดังที่ได้กล่าวมาแล้วการแก้ปัญหาเหล่านี้เป็นการรักษาความสงบเรียบร้อย - พวกเขาถือว่ามีลำดับที่เกี่ยวข้องระหว่างรายการ โซลูชันที่ไม่ได้เรียงลำดับจะแตกต่างกันสองชุด
pylang

4

นี่เป็นวิธีแก้ปัญหาอื่น:

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


4

สมมติว่าเรามีสองรายการ

list1 = [1, 3, 5, 7, 9]
list2 = [1, 2, 3, 4, 5]

เราสามารถเห็นได้จากรายการด้านบนสองรายการที่มีรายการ 1, 3, 5 อยู่ในรายการ 2 และรายการ 7, 9 ไม่มี ในทางกลับกันรายการ 1, 3, 5 มีอยู่ในรายการ 1 และรายการ 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


3

ถ้าคุณต้องการอะไรมากกว่าชุดเซ็ตการแก้ไข ...

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"

2

เราสามารถคำนวณทางแยกด้วยการรวมหลายรายการ:

temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two', 'Five']

set(temp1+temp2)-(set(temp1)&set(temp2))

Out: set(['Four', 'Five', 'Three']) 

2

สิ่งนี้สามารถแก้ไขได้ด้วยหนึ่งบรรทัด คำถามจะได้รับสองรายการ (temp1 และ temp2) คืนความแตกต่างในรายการที่สาม (temp3)

temp3 = list(set(temp1).difference(set(temp2)))

1

นี่เป็นวิธีง่ายๆในการแยกความแตกต่างสองรายการ (ไม่ว่าเนื้อหาจะเป็นอย่างไร) คุณสามารถรับผลลัพธ์ดังที่แสดงด้านล่าง:

>>> 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])

หวังว่านี่จะเป็นประโยชน์


0

ฉันชอบที่จะใช้การแปลงเป็นชุดแล้วใช้ฟังก์ชัน "different ()" รหัสเต็มคือ:

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']

เป็นวิธีที่ง่ายที่สุดในการทำความเข้าใจและวางอนาคตในอนาคตหากคุณทำงานกับข้อมูลขนาดใหญ่การแปลงเป็นชุดจะเป็นการลบรายการที่ซ้ำกันหากไม่จำเป็นต้องทำซ้ำ หวังว่าจะช่วย ;-)


-1
(list(set(a)-set(b))+list(set(b)-set(a)))

3
นอกเหนือจากการให้คำตอบคุณสามารถให้คำอธิบายเกี่ยวกับวิธีการทำงาน / นำไปใช้กับปัญหาเฉพาะนี้ได้หรือไม่? คำตอบและวิธีแก้ปัญหานั้นยอดเยี่ยม แต่คำแนะนำและคำอธิบายโดยละเอียดนั้นดีกว่ามาก
Busse

-1
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]


คุณไม่สามารถทำเช่นนี้เพื่อการดำเนินงานที่แตกต่างกัน แม้ในกรณีที่เป็นจำนวนเต็มถ้าคุณบอกให้ฟังก์ชั่น 'a - b' มันก็ควรจะลบ 'b' จาก 'a' เท่านั้นไม่ว่า 'b' จะใหญ่กว่า 'a' หรืออย่างอื่นก็ตาม ที่คล้ายกันเป็นกรณีที่มีรายการและชุด A - B และ B - A ทั้งสองสามารถดำเนินการที่ถูกต้องโดยไม่คำนึงถึงความยาวของ A และ B คุณเพียงแค่ต้องแยกเนื้อหาของ B จาก A เพื่อดำเนินการ A - B.
Abu Talha Danish
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.