পাইথন, গণনা তালিকার পার্থক্য


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)থেটার (এন ensure 2) এর পরিবর্তে অ্যালগরিদমকে ও (এনলগন) হয় তা নিশ্চিত করার জন্য ব্যবহারের কথা বিবেচনা করুন
নীল জি

8
@ পেনসিলচেক - আপনি যদি এ এ আদেশ বা নকলের বিষয়ে চিন্তা করেন setতবে বি তে আবেদন করা নিরীহ নয়, তবে এটি প্রয়োগ Aএবং মূলটির পরিবর্তে ফলাফলটি ব্যবহার Aকরা নয়।
মার্ক রিড

1
@ নীলজি আপনি সেটটি তৈরি করতে ব্যয় করা সময় বিবেচনা করছেন? আমার ক্ষেত্রে (উভয় তালিকার প্রায় 10 এম স্ট্রিং রয়েছে) দুটি সেট বানাতে এবং বিয়োগের সময়গুলি একটি সেট তৈরি করা এবং তালিকার উপরে পুনরাবৃত্ত হওয়ার চেয়ে যথেষ্ট বড়।
ডিসিম্রিল

@ ডিমরিল যদি আপনি এটি করতে চান তবে আপনার আরও পরিশীলিত কিছু প্রয়োগ করা উচিত। উদাহরণস্বরূপ আপনি উভয় তালিকাগুলি হে (এন লগ এন + এম লগ এম) এবং বাছাই করতে পারেন এবং দ্বিতীয় তালিকায় পুনরাবৃত্তি করতে পারেন তবে প্রথম তালিকার আইটেমগুলি সন্ধান করতে বাইনারি অনুসন্ধান ব্যবহার করুন use এটি ও (এন লগ এন + এম লগ এম + এম লগ এন) অপারেশনগুলিতে (ও (এন * মি) অপারেশনগুলির পরিবর্তে) আসবে, যা খুব খারাপ বলে মনে হয় না। আপনার বাইনারি অনুসন্ধানের প্রয়োগগুলিতে সদৃশগুলিও মুছে ফেলতে প্রতিবেশীদের পরীক্ষা করার বিষয়টি নিশ্চিত করুন। এমনকি এমন প্যাকেজও থাকতে পারে যা ইতিমধ্যে এটি প্রয়োগ করে, তবে আমি পরীক্ষা করে দেখিনি।
jaaq

364

যদি অর্ডারটি কোনও বিষয় না দেয় তবে আপনি কেবল সেট পার্থক্যটি গণনা করতে পারেন:

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

9
এটি এখন পর্যন্ত সেরা সমাধান is Each 6000 স্ট্রিং সহ তালিকাগুলিতে টেস্ট কেস দেখিয়েছে যে তালিকাটি বোঝার চেয়ে প্রায় 100x দ্রুত এই পদ্ধতিটি ছিল।
পেরিওজিও

15
আবেদনের উপর নির্ভর করে: যদি অর্ডার বা সদৃশ সংরক্ষণ গুরুত্বপূর্ণ তবে রোমান বোদনারচুকের আরও ভাল পদ্ধতির থাকতে পারে। গতি এবং খাঁটি সেট-এর মতো আচরণের জন্য এটি আরও ভাল বলে মনে হয়।
ব্রায়ান পি

7
তালিকার একাধিক সমান উপাদান থাকলে এই সমাধানটি কাজ করবে না।
করানটান

তালিকা বোঝার চেয়ে অনেক বেশি ভাল।
দাউই

4
এই সমাধানটি এত সুস্পষ্ট বলে মনে হচ্ছে তবে এটি ভুল। আমি দুঃখিত. অবশ্যই আমরা বোঝাতে চাইছি যে একটি তালিকাতে বারবার সমান উপাদান থাকতে পারে। অন্যথায় আমরা সেট পার্থক্য সম্পর্কে জিজ্ঞাসা করি, তালিকার পার্থক্য সম্পর্কে নয়।
সার্জাজাচ

67

আপনি একটি করতে পারেন

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

এবং

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

7
তবে যদি এ = [1,1,1] এবং বি = [0] হয় তবে এটি ফিরে আসে [1]
মার্ক বেল

1
@ মার্ক বেল: হ'ল কারণ একটি সেট একটি স্বতন্ত্র তালিকা। (সদৃশ অপসারণ)
মেঘ

1
@ ক্লাউডি তারপর এই প্রশ্নের উত্তর দেয় না।
samm82

@ samm82 যদি সেট = (এ) এর তুলনায় A = [1,1,1] হয় [1] কারণ সেটটি একটি স্বতন্ত্র তালিকা এবং সদৃশগুলি সরিয়ে দেয়। কেন, যদি এ = [1,1,1] এবং বি = [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 পান যা আমি আগে দেখিনি। তবুও, আমি সম্মত নই যে উপরোক্ত উত্তরগুলি সমস্যাটি তুচ্ছ হিসাবে বর্ণনা করেছে
rbp

ডিফ্লিব ব্যবহার করার জন্য ধন্যবাদ - আমি স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে একটি সমাধান খুঁজছিলাম। তবে এটি পাইথন 3 এ কাজ করছে না, যেমন printএকটি কমান্ড থেকে কোনও ফাংশনে পরিবর্তিত হয়েছে এবং reduce, filterএবং mapঅযৌক্তিক ঘোষিত হয়েছে। (এবং আমি মনে করি গাইডো সঠিক হতে পারে - আমি যা বুঝতে পারি তাও বুঝতে পারি না reduce))
019

এটি পাই 3 এর জন্য কাজ করতে কোনও বড় শিফট নয়। আমি ফিল্টার, মানচিত্র, হ্রাস এবং ফিন্টুলগুলিতে ফিল্টারের বিকল্প ইমপ্লিটকে ধাক্কা দেওয়ার নির্বাচনের সাথে বিতর্কটি পড়েছি। অজগরটির মিশ্র ক্রিয়ামূলক, ওও এবং পদ্ধতিগত প্রকৃতি সর্বদা আইএমও, এর অন্যতম শক্তি।
কেভিন

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/DPdiff

স্থাপন

পিপিআই থেকে ইনস্টল করুন:

pip install deepdiff

আপনি পাইথন 3 হলে আপনাকে ইনস্টল করতে হবে:

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


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

ইন-অপারেটরের টাইম কমপ্লিটটি একবার দেখার জন্য, সবচেয়ে খারাপ ক্ষেত্রে এটি ও (এন) এর সাথে কাজ করে। এমনকি সেট জন্য।

সুতরাং দুটি অ্যারের তুলনা করার সময় আমাদের কাছে সবচেয়ে ভাল ক্ষেত্রে ও (এন) এবং ও (এন ity 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]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.