সংক্ষিপ্ত উত্তর : ব্যবহার করুন 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([]))
ফলস ফলস। এবং অবশ্যই যদি আপনি আপনার তালিকাগুলি সেট হিসাবে সেট করে রাখেন তবে আপনি সেট ওভারহেড সেটটি সংরক্ষণ করবেন।