python - दो सूचियों के बीच अंतर प्राप्त करें




performance list (15)

मेरे पास पाइथन में दो सूचियां हैं, जैसे:

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

मुझे पहली सूची में मौजूद वस्तुओं के साथ तीसरी सूची बनाने की आवश्यकता है जो दूसरे में मौजूद नहीं हैं। उदाहरण से मुझे यह प्राप्त करना है:

temp3 = ['Three', 'Four']

क्या चक्र और जांच के बिना कोई तेज तरीका है?


इसे इस्तेमाल करे:

temp3 = set(temp1) - set(temp2)

इसे एक लाइन के साथ हल किया जा सकता है। प्रश्न दो सूचियों (temp1 और temp2) को तीसरे सूची (temp3) में अपना अंतर वापस कर दिया गया है।

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

पायथन एक्सओआर ऑपरेटर का उपयोग करके किया जा सकता है।

  • यह प्रत्येक सूची में डुप्लीकेट हटा देगा
  • यह temp1 से temp1 और temp2 से temp1 का अंतर दिखाएगा।
set(temp1) ^ set(temp2)

मैं इसके लिए खेल में बहुत देर हो चुकी हूं लेकिन आप उपरोक्त उल्लिखित कोड के कुछ प्रदर्शनों की तुलना कर सकते हैं, दो सबसे तेज दावेदार हैं,

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

मैं टॉस करूंगा क्योंकि वर्तमान में से कोई भी समाधान टुपल नहीं देता है:

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

इस दिशा में उत्तर देने वाले अन्य गैर-टुपल की तरह, यह आदेश को संरक्षित करता है


मौजूदा समाधान सभी या तो एक या दूसरे की पेशकश करते हैं:

  • ओ (एन * एम) प्रदर्शन से तेज़।
  • इनपुट सूची का क्रम बचाओ।

लेकिन अब तक कोई समाधान नहीं है। यदि आप दोनों चाहते हैं, तो इसे आजमाएं:

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

यदि आप कुछ बदलाव की तरह कुछ चाहते हैं ... काउंटर का उपयोग कर सकते हैं

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"

यदि आप बार-बार अंतर चाहते हैं, तो मैंने पायथन के लिए एक पैकेज लिखा है: https://github.com/seperman/deepdiff

स्थापना

पीपीपीआई से स्थापित करें:

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

यदि भिन्नता के तत्व क्रमबद्ध और सेट होते हैं तो आप एक बेवकूफ विधि का उपयोग कर सकते हैं।

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.9 9 8837615564


यह एक और समाधान है:

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

सबसे आसान तरीका है,

सेट सेट () अंतर (सेट ())

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

सबसे सरल मामले के लिए 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']

Arulmr समाधान का एकल लाइन संस्करण

def diff(listA, listB):
    return set(listA) - set(listB) | set(listA) -set(listB)

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

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




set-difference