पायथन, गणना सूची अंतर


195

पायथन में, दो सूचियों के बीच अंतर की गणना करने का सबसे अच्छा तरीका क्या है?

उदाहरण

A = [1,2,3,4]
B = [2,5]

A - B = [1,3,4]
B - A = [5]

जवाबों:


206

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

31
set(b)थीटा (n ^ 2) के बजाय एल्गोरिथ्म हे (nlogn) सुनिश्चित करने के लिए उपयोग करने पर विचार करें
नील जी

8
@ पेन्सिलचेक - यदि आप ए में आदेश देने या नकल करने की परवाह नहीं करते हैं, तो setबी को लागू करना हानिरहित है, लेकिन Aमूल के बजाय परिणाम के लिए इसे लागू करना और उपयोग करना Aनहीं है।
मार्क रीड

1
@NeilG क्या आप सेट बनाने में लगने वाले समय को मानते हैं? मेरे मामले में (दोनों सूचियों में लगभग 10 मीटर स्ट्रिंग्स हैं) दो सेट बनाने और उन्हें घटाने के लिए एक सेट बनाने और सूची से अधिक पुनरावृत्ति करने की तुलना में काफी बड़ा है।
डिमरील

@dimril यदि आप ऐसा करना चाहते हैं तो शायद आपको कुछ अधिक परिष्कृत तरीके से लागू करना चाहिए। आप उदाहरण के लिए दोनों सूची O (n लॉग एन + एम लॉग एम) को सॉर्ट कर सकते हैं और फिर दूसरी सूची पर पुनरावृति कर सकते हैं लेकिन पहली सूची में आइटम खोजने के लिए द्विआधारी खोज का उपयोग कर सकते हैं। यह O (n log n + m log m + m log n) ऑपरेशंस (O (n * m) ऑपरेशंस के बजाय) के लिए आएगा, जो बहुत बुरा नहीं लगता। बस अपने द्विआधारी खोज कार्यान्वयन में डुप्लिकेट को समाप्त करने के लिए पड़ोसियों की जांच करना सुनिश्चित करें। यहां तक ​​कि एक पैकेज भी हो सकता है जो पहले से ही इसे लागू करता है, लेकिन मैंने जांच नहीं की।
jaq

366

यदि आदेश से कोई फर्क नहीं पड़ता है, तो आप बस निर्धारित अंतर की गणना कर सकते हैं:

>>> set([1,2,3,4]) - set([2,5])
set([1, 4, 3])
>>> set([2,5]) - set([1,2,3,4])
set([5])

9
यह अब तक का सबसे अच्छा समाधान है। ~ 6000 स्ट्रिंग्स के साथ सूचियों पर परीक्षण मामले से पता चला है कि यह विधि सूची समझ से लगभग 100x तेज थी।
पेरीजियो

15
आवेदन पर निर्भर करता है: यदि आदेश या दोहराव संरक्षण महत्वपूर्ण है रोमन बोडर्नेचुक एक बेहतर दृष्टिकोण हो सकता है। गति और शुद्ध सेट-जैसे व्यवहार के लिए यह बेहतर लगता है।
ब्रायन पी

7
यदि आपके पास सूची में कई समान तत्व हैं तो यह समाधान काम नहीं करेगा।
कार्तन

सूची की समझ से कहीं अधिक बेहतर।
डावी

4
यह समाधान इतना स्पष्ट है लेकिन यह गलत है। मुझे माफ कर दो। बेशक हमारा मतलब है कि एक सूची में समान तत्वों को दोहराया जा सकता है। अन्यथा हम सेट के अंतर के बारे में पूछते हैं, न कि सूची के अंतर के बारे में।
सर्जक

67

आप एक कर सकते हैं

list(set(A)-set(B))

तथा

list(set(B)-set(A))

7
लेकिन अगर A = [1,1,1] और B = [0] तो यह रिटर्न करता है [1]
मार्क बेल

1
@ मर्क बेल: थॉट्स क्योंकि एक सेट एक अलग सूची है। (हटा डुप्लिकेट)
बादल छाए रहेंगे

1
@cloudy तो यह सवाल का जवाब नहीं है।
शाम 82

@ samm82 अगर ए = [११,११] सेट (ए) से है [१] क्योंकि सेट एक अलग सूची है और डुप्लिकेट को हटाता है। यही कारण है कि, यदि A = [1,1,1] और B = [0] यह [1] रिटर्न करता है।
बादल छाए रहेंगे


14

उपरोक्त उदाहरणों ने मतभेदों की गणना की समस्या को तुच्छ बताया। छंटाई या डी-डुप्लिकेट मानने से निश्चित रूप से अंतर की गणना करना आसान हो जाता है, लेकिन यदि आपकी तुलना उन मान्यताओं को बर्दाश्त नहीं कर सकती है, तो आपको एक अलग एल्गोरिथ्म के गैर-तुच्छ कार्यान्वयन की आवश्यकता होगी। अजगर मानक पुस्तकालय में डिफ्लिब देखें।

from difflib import SequenceMatcher 

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

ए - बी = [[१, ३, ४]]


1
आपको डिफ्लिब के लिए +1 मिलता है, जो मैंने पहले नहीं देखा था। फिर भी, मैं इस बात से सहमत नहीं हूं कि उपर्युक्त उत्तर समस्या के रूप में बताए गए हैं
आरबीपी

डिफ्लिब का उपयोग करने के लिए धन्यवाद - मैं मानक पुस्तकालय का उपयोग करके एक समाधान की तलाश कर रहा था। हालाँकि, यह पायथन 3 में काम नहीं कर रहा है, जैसा printकि एक कमांड से एक फ़ंक्शन में बदल गया है, और reduce, filterऔर mapइसे अनफ़िथोनिक घोषित किया गया है। (और मुझे लगता है कि गुइडो सही हो सकता है - मुझे समझ में नहीं आता कि क्या reduceकरता है, या तो।)
Post169

यह py3 के लिए काम करने के लिए एक बड़ी पारी नहीं है। मैंने फ़िल्टर पर चर्चा की है, मैप को कम किया है और कम करने के विकल्प के साथ सहमति व्यक्त की है और फ़िल्टर में प्रत्यारोपित करने के लिए वैकल्पिक रूप से रूपांतरण किया है। अजगर की मिश्रित कार्यात्मक, OO और प्रक्रियात्मक प्रकृति हमेशा से, IMO, इसकी एक ताकत रही है।
केविन

14

पायथन 2.7.3 (डिफ़ॉल्ट, 27 फरवरी 2014, 19:58:35) - आईपीथॉन 1.1.0 - समय: ( गीथूब जिस्ट )

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'

@ रोमन-बोडनार्चुक लिस्ट कॉम्प्रिहेंशन फंक्शन डिफ डिफरेंस (ए, बी) तेजी से लगता है।




5

यदि आप चाहते हैं कि अंतर आपकी सूची के मदों में गहराई से जा रहा है, तो मैंने अजगर के लिए एक पैकेज लिखा है: 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!

स्ट्रिंग अंतर २

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


2

शब्दकोशों की एक सूची के मामले में , पूरी सूची समझने वाला समाधान काम करता है जबकि 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}]

0

यदि आप चाहते हैं कि सरल कोड आपको कई मदों के साथ अंतर देता है:

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)

-1

जब इन-ऑपरेटर के TimeComplexity को देखते हैं , तो सबसे खराब स्थिति में यह O (n) के साथ काम करता है। यहां तक ​​कि सेट्स के लिए भी।

इसलिए जब दो सरणियों की तुलना करते हैं तो हमारे पास सबसे अच्छे मामले में O (n) का TimeComplexity और सबसे खराब स्थिति में O (n ^ 2) होगा।

एक वैकल्पिक (लेकिन दुर्भाग्य से अधिक जटिल) समाधान, जो ओ (एन) के साथ काम करता है सबसे अच्छा और सबसे खराब स्थिति में यह एक है:

# 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]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.