संक्षिप्त उत्तर : उपयोग not set(a).isdisjoint(b)
, यह आमतौर पर सबसे तेज़ है।
दो सूचियों को सूचीबद्ध करने a
और b
किसी भी आइटम को साझा करने के लिए चार सामान्य तरीके हैं । पहला विकल्प यह है कि दोनों को सेट करें और उनके प्रतिच्छेदन की जाँच करें, जैसे:
bool(set(a) & set(b))
क्योंकि पायथन में हैश टेबल का उपयोग करके सेट्स को संग्रहीत किया जाता है, उन्हें खोज रहा हैO(1)
( पायथन में ऑपरेटरों की जटिलता के बारे में अधिक जानकारी के लिए यहां देखें )। सैद्धांतिक रूप से, यह है O(n+m)
के लिए औसतन n
और m
सूचियों में वस्तुओं a
और b
। लेकिन 1) इसे पहले सूचियों से बाहर सेट बनाना होगा, जो समय की एक नगण्य राशि ले सकता है, और 2) यह मानता है कि हैशिंग टकराव आपके डेटा के बीच विरल हैं।
इसे करने का दूसरा तरीका सूची में पुनरावृत्ति प्रदर्शन कर रहे एक जनरेटर अभिव्यक्ति का उपयोग कर रहा है, जैसे:
any(i in a for i in b)
यह इन-प्लेस को खोजने की अनुमति देता है, इसलिए मध्यस्थ चर के लिए कोई नई मेमोरी आवंटित नहीं की जाती है। यह पहली खोज पर भी निकल जाता है। लेकिन in
ऑपरेटर हमेशा O(n)
सूचियों पर होता है ( यहां देखें )।
एक अन्य प्रस्तावित विकल्प सूची में से एक के माध्यम से एक हाइब्रिडो पुनरावृति है, दूसरे को एक सेट में परिवर्तित करें और इस सेट पर सदस्यता के लिए परीक्षण करें, जैसे:
a = set(a); any(i in a for i in b)
चौथा दृष्टिकोण उदाहरण isdisjoint()
के लिए (जमे हुए) सेट ( यहां देखें) की विधि का लाभ उठाना है :
not set(a).isdisjoint(b)
यदि आपके द्वारा खोजे जाने वाले तत्व एक सरणी की शुरुआत के पास हैं (जैसे कि इसे क्रमबद्ध किया गया है), तो जनरेटर अभिव्यक्ति का पक्ष लिया जाता है, क्योंकि सेट चौराहे की विधि को मध्यस्थ चर के लिए नई मेमोरी आवंटित करनी होती है:
from timeit import timeit
>>> timeit('bool(set(a) & set(b))', setup="a=list(range(1000));b=list(range(1000))", number=100000)
26.077727576019242
>>> timeit('any(i in a for i in b)', setup="a=list(range(1000));b=list(range(1000))", number=100000)
0.16220548999262974
सूची आकार के कार्य में इस उदाहरण के लिए निष्पादन समय का एक ग्राफ यहां दिया गया है:
ध्यान दें कि दोनों कुल्हाड़ी लॉगरिदमिक हैं। यह जनरेटर अभिव्यक्ति के लिए सबसे अच्छा मामला दर्शाता है। जैसा कि देखा जा सकता है, isdisjoint()
विधि बहुत छोटी सूची आकारों के लिए बेहतर है, जबकि बड़ी सूची आकारों के लिए जनरेटर की अभिव्यक्ति बेहतर है।
दूसरी ओर, जैसा कि हाइब्रिड और जनरेटर अभिव्यक्ति के लिए खोज शुरू होती है, अगर साझा तत्व व्यवस्थित रूप से सरणी के अंत में है (या दोनों सूची किसी भी मूल्य को साझा नहीं करता है), तो असहमति और सेट चौराहे दृष्टिकोण तब होते हैं जनरेटर की अभिव्यक्ति और हाइब्रिड दृष्टिकोण की तुलना में अधिक तेज़।
>>> timeit('any(i in a for i in b)', setup="a=list(range(1000));b=[x+998 for x in range(999,0,-1)]", number=1000))
13.739536046981812
>>> timeit('bool(set(a) & set(b))', setup="a=list(range(1000));b=[x+998 for x in range(999,0,-1)]", number=1000))
0.08102107048034668
यह ध्यान रखना दिलचस्प है कि जनरेटर की अभिव्यक्ति बड़े सूची आकारों के लिए धीमी है। यह पिछले आंकड़े के लिए 100000 के बजाय केवल 1000 पुनरावृत्ति के लिए है। जब कोई तत्व साझा नहीं किए जाते हैं, तो यह सेटअप अच्छी तरह से अनुमानित हो जाता है, और तिरस्कार और सेट चौराहे के दृष्टिकोण के लिए सबसे अच्छा मामला है।
यहां यादृच्छिक संख्याओं का उपयोग करके दो विश्लेषण किए गए हैं (एक तकनीक या किसी अन्य का पक्ष लेने के लिए सेटअप को हेराफेरी करने के बजाय):
साझा करने का उच्च मौका: तत्वों को यादृच्छिक रूप से लिया जाता है [1, 2*len(a)]
। साझा करने की कम संभावना: तत्वों को यादृच्छिक रूप से लिया जाता है [1, 1000*len(a)]
।
अब तक, यह विश्लेषण माना जाता है कि दोनों सूचियाँ एक ही आकार की हैं। विभिन्न आकारों की दो सूचियों के मामले में, उदाहरण के a
लिए बहुत छोटा है, isdisjoint()
हमेशा तेज होता है:
सुनिश्चित करें कि a
सूची छोटी है, अन्यथा प्रदर्शन कम हो जाता है। इस प्रयोग में, a
सूची आकार स्थिर था 5
।
संक्षेप में:
- यदि सूचियाँ बहुत छोटी हैं (<10 तत्व),
not set(a).isdisjoint(b)
हमेशा सबसे तेज़ होती है।
- यदि सूचियों के तत्वों को क्रमबद्ध किया जाता है या एक नियमित संरचना होती है जिसका आप लाभ उठा सकते हैं, तो जनरेटर अभिव्यक्ति
any(i in a for i in b)
बड़े सूची आकारों पर सबसे तेज़ है;
- सेट चौराहे का परीक्षण करें
not set(a).isdisjoint(b)
, जो हमेशा की तुलना में तेज होता है bool(set(a) & set(b))
।
- हाइब्रिड "सूची के माध्यम से पुनरावृति, सेट पर परीक्षण"
a = set(a); any(i in a for i in b)
आम तौर पर अन्य तरीकों की तुलना में धीमी है।
- जनरेटर अभिव्यक्ति और हाइब्रिड दो अन्य दृष्टिकोणों की तुलना में बहुत धीमा है जब यह तत्वों को साझा किए बिना सूचियों में आता है।
ज्यादातर मामलों में, isdisjoint()
विधि का उपयोग करना सबसे अच्छा तरीका है क्योंकि जनरेटर अभिव्यक्ति को निष्पादित करने में अधिक समय लगेगा, क्योंकि यह बहुत अक्षम है जब कोई तत्व साझा नहीं किए जाते हैं।
len(...) > 0
क्योंकिbool(set([]))
फाल्स की पैदावार होती है। और निश्चित रूप से अगर आप अपनी सूची को सेट के रूप में शुरू करते हैं तो आप सेट ओवरहेड को बचाएंगे।