पायथन में दो अनियंत्रित सूचियों (सेट नहीं) की कुशलता से तुलना कैसे करें?


141
a = [1, 2, 3, 1, 2, 3]
b = [3, 2, 1, 3, 2, 1]

ए और बी को समान माना जाना चाहिए, क्योंकि उनके पास एक ही तत्व हैं, केवल अलग-अलग क्रम में।

बात यह है, मेरी वास्तविक सूचियाँ ऑब्जेक्ट्स (मेरी कक्षा के उदाहरण) से युक्त होंगी, पूर्णांक नहीं।


7
वस्तुओं की तुलना कैसे की जाती है?
मार्सेलो कैंटोस

2
वास्तविक सूचियों का अपेक्षित आकार क्या है? क्या सूचियों की तुलना तुलनात्मक आकार की होगी या बहुत भिन्न होगी? क्या आप अधिकांश सूचियों के मिलान की अपेक्षा करते हैं या नहीं?
दिमित्री बी।

कोई len()पहले जाँच कर सकता है ।
ग्रेबियर

जवाबों:


245

O (n) : काउंटर () विधि सबसे अच्छी है (यदि आपकी वस्तुएं हैं):

def compare(s, t):
    return Counter(s) == Counter(t)

O (n लॉग एन) : सॉर्ट किया गया () विधि सबसे अच्छा है (यदि आपकी वस्तुएं क्रमबद्ध हैं):

def compare(s, t):
    return sorted(s) == sorted(t)

O (n * n) : यदि वस्तुएं न तो धोने योग्य हैं, न ही ऑर्डर करने योग्य हैं, तो आप समानता का उपयोग कर सकते हैं:

def compare(s, t):
    t = list(t)   # make a mutable copy
    try:
        for elem in s:
            t.remove(elem)
    except ValueError:
        return False
    return not t

1
धन्यवाद। मैंने प्रत्येक ऑब्जेक्ट को एक स्ट्रिंग में परिवर्तित किया फिर काउंटर () पद्धति का उपयोग किया।
जोहंदिर

अरे @ रेमंड, मुझे हाल ही में एक साक्षात्कार पर इस सवाल का सामना करना पड़ा और मैंने इसका इस्तेमाल किया sorted(), जिसके बारे में मुझे नहीं पता था Counter। साक्षात्कारकर्ता ने जोर देकर कहा कि एक अधिक कुशल तरीका था और स्पष्ट रूप से मैंने एक रिक्त को आकर्षित किया। timeitमॉड्यूल के साथ अजगर 3 में व्यापक परीक्षण के बाद , सॉर्टर्स लगातार पूर्णांक की सूचियों पर तेजी से निकलता है। की सूची पर, 1k आइटम, के बारे में 1.5% धीमी और छोटी सूची पर, 10 आइटम, 7.5% धीमी है। विचार?
6

4
छोटी सूचियों के लिए, बड़े-ओ विश्लेषण आमतौर पर अप्रासंगिक होते हैं क्योंकि निरंतर कारकों में समय का प्रभुत्व होता है। लंबी सूचियों के लिए, मुझे संदेह है कि आपके बेंचमार्किंग में कुछ गड़बड़ है। 5 के साथ 100 ints के लिए प्रत्येक दोहराता है, मुझे मिलता है: सॉर्ट किए गए 127 usec और काउंटर के लिए 42 (लगभग 3x तेज)। ५ रिपीट के साथ १००० इन्ट्स पर, काउंटर ४x तेज है। python3.6 -m timeit -s 'from collections import Counter' -s 'from random import shuffle' -s 't=list(range(100)) * 5' -s 'shuffle(t)' -s 'u=t[:]' -s 'shuffle(u)' 'Counter(t)==Counter(u)'
रेमंड हेटिंगर

@ रेमंड वास्तव में हमें अलग-अलग परिणाम मिल रहे हैं। मैंने अपना सेटअप एक चैट रूम में पोस्ट किया है sorted vs counter.. मैं बहुत उत्सुक हूँ कि यहाँ क्या हो रहा है।
आर्केलिक्स

4
जी नहीं, धन्यवाद। मुझे स्पुरियस टाइमिंग स्क्रिप्ट्स डीबग करने में अधिक रुचि नहीं है। यहां बहुत कुछ चल रहा है (शुद्ध अजगर बनाम सी कोड, समयबद्ध डेटा बनाम अर्ध-ऑर्डर किए गए डेटा पर लागू किया जा रहा है, संस्करणों में अलग-अलग कार्यान्वयन विवरण, डेटा में कितने डुप्लिकेट हैं, आदि)
रेमंड हेटिंगटन

16

आप दोनों को सॉर्ट कर सकते हैं:

sorted(a) == sorted(b)

एक प्रकार की गिनती भी अधिक कुशल हो सकती है (लेकिन इसमें वस्तु को धोने योग्य होना आवश्यक है)।

>>> from collections import Counter
>>> a = [1, 2, 3, 1, 2, 3]
>>> b = [3, 2, 1, 3, 2, 1]
>>> print (Counter(a) == Counter(b))
True

काउंटर हैशिंग का उपयोग करता है, लेकिन ऑब्जेक्ट प्रति सीसेबल नहीं हैं। आपको बस एक समझदार को लागू करना है __hash__, लेकिन यह संग्रह के लिए असंभव हो सकता है।
जोचेन रिट्जेल

2
सॉर्ट किए गए सभी चीज़ों के लिए काम नहीं करेगा, जैसे कि जटिल नंबरsorted([0, 1j])
जॉन ला रोय ऑक्ट

1
सॉर्ट किए गए () सेट के साथ भी काम नहीं करते हैं जहां तुलना ऑपरेटरों को सबसेट / सुपरसेट टेस्ट के लिए ओवरराइड किया गया है।
रेमंड हेटिंगर

12

यदि आप जानते हैं कि आइटम हमेशा धोने योग्य होते हैं, तो आप Counter()O का उपयोग कर सकते हैं (n)
यदि आप जानते हैं कि आइटम हमेशा सॉर्टेबल होते हैं, तो आप sorted()O (n लॉग एन) का उपयोग कर सकते हैं

सामान्य स्थिति में, आप छँटाई करने में सक्षम नहीं हो सकते हैं या तत्व नहीं हो सकते हैं, इसलिए आपको इस तरह की गिरावट की आवश्यकता है, जो दुर्भाग्य से हे (n ^ 2)

len(a)==len(b) and all(a.count(i)==b.count(i) for i in a)

5

ऐसा करने का सबसे अच्छा तरीका सूचियों को क्रमबद्ध करना और उनकी तुलना करना है। (उपयोग Counterकरने योग्य नहीं है कि वस्तुओं के साथ काम नहीं करेगा।) यह पूर्णांकों के लिए सीधा है:

sorted(a) == sorted(b)

यह मनमाना वस्तुओं के साथ थोड़ा पेचीदा हो जाता है। आप, वस्तु पहचान, यानी के बारे में परवाह है कि क्या अगर एक ही वस्तुओं दोनों सूचियों में हैं, तो आप उपयोग कर सकते हैं id()प्रकार कुंजी के रूप में कार्य करते हैं।

sorted(a, key=id) == sorted(b, key==id)

(पायथन 2.x में आपको वास्तव में key=पैरामीटर की आवश्यकता नहीं है , क्योंकि आप किसी भी वस्तु की किसी भी वस्तु से तुलना कर सकते हैं। ऑर्डर मनमाना है, लेकिन स्थिर है, इसलिए यह इस उद्देश्य के लिए ठीक काम करता है; इससे कोई फर्क नहीं पड़ता कि वस्तुएं क्या ऑर्डर करती हैं। में, केवल यह कि दोनों सूचियों के लिए ऑर्डरिंग समान है। पायथन 3 में, हालांकि, विभिन्न प्रकारों की वस्तुओं की तुलना करना कई परिस्थितियों में अस्वीकृत है - उदाहरण के लिए, आप तार की तुलना पूर्णांक से नहीं कर सकते - इसलिए यदि आपके पास ऑब्जेक्ट होंगे विभिन्न प्रकार के, स्पष्ट रूप से ऑब्जेक्ट की आईडी का उपयोग करने के लिए सबसे अच्छा।)

यदि आप सूची में वस्तुओं की तुलना मूल्य से करना चाहते हैं , तो दूसरी ओर, आपको पहले यह परिभाषित करने की आवश्यकता है कि वस्तुओं के लिए "मूल्य" का क्या अर्थ है। फिर आपको एक कुंजी के रूप में (और पायथन 3 के लिए, एक सुसंगत प्रकार के रूप में) प्रदान करने के लिए कुछ तरीके की आवश्यकता होगी। एक संभावित तरीका जो बहुत सारी मनमानी वस्तुओं के लिए काम करेगा, उनके द्वारा सॉर्ट करना है repr()। बेशक, यह repr()बड़ी सूची और इतने पर अतिरिक्त समय और मेमोरी बिल्डिंग स्ट्रिंग्स को बर्बाद कर सकता है ।

sorted(a, key=repr) == sorted(b, key==repr)

यदि ऑब्जेक्ट्स आपके सभी प्रकार के हैं, तो आप __lt__()उन्हें परिभाषित कर सकते हैं ताकि ऑब्जेक्ट जानता हो कि दूसरों से खुद की तुलना कैसे करें। तब आप बस उन्हें क्रमबद्ध कर सकते हैं और key=पैरामीटर की चिंता नहीं कर सकते । बेशक आप परिभाषित __hash__()और उपयोग भी कर सकते हैं Counter, जो तेज होगा।


4

https://docs.python.org/3.5/library/unittest.html#unittest.TestCase.assertCountEqual

assertCountEqual (पहला, दूसरा, संदेश = कोई नहीं)

परीक्षण करें कि अनुक्रम में पहले समान तत्व शामिल हैं, भले ही उनके आदेश की परवाह किए बिना। जब वे नहीं करते हैं, तो अनुक्रमों के बीच के अंतर को सूचीबद्ध करने वाला एक त्रुटि संदेश उत्पन्न होगा।

पहले और दूसरे की तुलना करते समय डुप्लिकेट तत्वों को नजरअंदाज नहीं किया जाता है। यह सत्यापित करता है कि दोनों अनुक्रमों में प्रत्येक तत्व की एक ही गणना है या नहीं। समतुल्य: assertEqual (काउंटर (सूची (प्रथम)), काउंटर (सूची (दूसरा))) लेकिन साथ ही साथ निर्विवाद वस्तुओं के अनुक्रम के साथ काम करता है।

संस्करण 3.2 में नया।

या 2.7 में: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.assertItemsEqual


2
(क्या करने के लिए इस ऐड करता jarekwg के जवाब ?)
बूढ़ा

3

यदि सूची में वे आइटम शामिल हैं जो कि नहीं हैं (जैसे कि वस्तुओं की सूची) तो आप काउंटर क्लास और आईडी () फ़ंक्शन का उपयोग करने में सक्षम हो सकते हैं :

from collections import Counter
...
if Counter(map(id,a)) == Counter(map(id,b)):
    print("Lists a and b contain the same objects")

2

मुझे उम्मीद है कि नीचे का टुकड़ा आपके मामले में काम कर सकता है: -

if ((len(a) == len(b)) and
   (all(i in a for i in b))):
    print 'True'
else:
    print 'False'

यह है कि दोनों सूचियों में सभी तत्वों को यह सुनिश्चित करना होगा aऔर bएक ही हैं, चाहे वे उसी क्रम में हैं या नहीं की परवाह किए बिना।

बेहतर समझ के लिए, इस प्रश्न में मेरे उत्तर का संदर्भ लें


2

यदि तुलना एक परीक्षण संदर्भ में की जानी है, तो उपयोग assertCountEqual(a, b)( py>=3.2) और assertItemsEqual(a, b)( 2.7<=py<3.2) करें।

अस्वाभाविक वस्तुओं के अनुक्रमों पर भी काम करता है।


1

चलो, बी सूची

def ass_equal(a,b):
try:
    map(lambda x: a.pop(a.index(x)), b) # try to remove all the elements of b from a, on fail, throw exception
    if len(a) == 0: # if a is empty, means that b has removed them all
        return True 
except:
    return False # b failed to remove some items from a

उन्हें धोने योग्य बनाने या उन्हें क्रमबद्ध करने की आवश्यकता नहीं है।


1
हां, लेकिन यह O (n ** 2) है, जैसा कि कई अन्य पोस्टरों में कहा गया है, इसलिए इसका उपयोग केवल तभी किया जाना चाहिए जब अन्य तरीके काम न करें। यह भी aसमर्थन करता है pop(परस्पर है) और index(एक अनुक्रम है)। रेमंड की अस्मिता न तो जबकि गिब्बलर की केवल एक सीक्वेंस है।
agf

0

unittestमॉड्यूल का उपयोग करना आपको एक साफ और मानक दृष्टिकोण देता है।

import unittest

test_object = unittest.TestCase()
test_object.assertCountEqual(a, b)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.