पायथन सेट्स बनाम लिस्ट्स


187

पायथन में, कौन सी डेटा संरचना अधिक कुशल / शीघ्र है? यह मानते हुए कि यह आदेश मेरे लिए महत्वपूर्ण नहीं है और मैं वैसे भी डुप्लिकेट की जाँच कर रहा हूँ, क्या पायथन सूची की तुलना में पायथन सेट धीमा है?

जवाबों:


230

यह इस पर निर्भर करता है कि आप इसके साथ क्या करना चाहते हैं।

यह निर्धारित करने के लिए कि क्या कोई वस्तु सेट (जैसे x in s) में मौजूद है, लेकिन यह उनकी सामग्री पर पुनरावृत्ति करने के लिए सूचियों की तुलना में धीमी है, जब यह निर्धारित करने की बात आती है, तो सेट काफी तेज होते हैं।

आप समयसीमा मॉड्यूल का उपयोग करके देख सकते हैं कि आपकी स्थिति कितनी तेज़ है।


4
अपनी बात के लिए: "सेट काफी तेज हैं", अंतर्निहित कार्यान्वयन क्या है जो इसे तेज बनाता है?
ओवरएक्सचेंज

स्क्रिप्टिंग भाषाएँ अंतर्निहित कार्यान्वयन को छिपाना पसंद करती हैं, लेकिन यह स्पष्ट सादगी हमेशा एक अच्छी बात नहीं होती है, आपको सॉफ्टवेयर के एक टुकड़े को डिज़ाइन करते समय कुछ 'डेटा संरचना' जागरूकता की आवश्यकता होती है।
क्रिस्टोफ रूसो

4
सेट पुनरावृत्ति करते समय सूची की तुलना में काफी धीमा नहीं है।
omerfarukdogan

39
सेट और सूची दोनों में रैखिक समय पुनरावृत्ति है। यह कहने के लिए कि एक दूसरे की तुलना में "धीमा" है, गुमराह है और इस जवाब को पढ़ने वाले नए प्रोग्रामरों को भ्रमित करता है।
हाबनीत

@ शबनम अगर आप कह रहे हैं कि उन दोनों में रैखिक समय का चलना है। क्या इसका मतलब है कि उनके पास समान पुनरावृत्ति समय है? फिर क्या फर्क है?
मोहम्मद नौरेलिन

152

जब आप मूल्यों पर पुनरावृति करना चाहते हैं, तो सूची सेट की तुलना में थोड़ी तेज़ होती हैं।

हालाँकि, यदि आप किसी आइटम को उसके भीतर समाहित करना चाहते हैं, तो सेट सूची से काफी तेज़ हैं। वे केवल अद्वितीय आइटम शामिल कर सकते हैं।

यह पता चलता है कि ट्यूपल्स अपनी अपरिवर्तनीयता को छोड़कर लगभग उसी तरह सूचियों में प्रदर्शन करते हैं।

बार-बार दोहराना

>>> def iter_test(iterable):
...     for i in iterable:
...         pass
...
>>> from timeit import timeit
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = set(range(10000))",
...     number=100000)
12.666952133178711
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = list(range(10000))",
...     number=100000)
9.917098999023438
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = tuple(range(10000))",
...     number=100000)
9.865639209747314

निर्धारित करें कि क्या कोई वस्तु मौजूद है

>>> def in_test(iterable):
...     for i in range(1000):
...         if i in iterable:
...             pass
...
>>> from timeit import timeit
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = set(range(1000))",
...     number=10000)
0.5591847896575928
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = list(range(1000))",
...     number=10000)
50.18339991569519
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = tuple(range(1000))",
...     number=10000)
51.597304821014404

6
मैंने पाया है कि (आरंभिक सेट -> 5.5300979614257812) (प्रारंभिक सूची -> 1.8846848011016846) (प्रारंभिक ट्यूपल -> 1.8730108737945557) 12GB रैम के साथ मेरे इंटेल कोर i5 क्वाड कोर पर आकार 10,000 के आइटम। इस पर भी ध्यान दिया जाना चाहिए।
thePracticalOne

4
मैंने अब ऑब्जेक्ट निर्माण को हटाने के लिए कोड अपडेट किया है। टाइमटॉप छोरों का सेटअप चरण केवल एक बार ( docs.python.org/2/library/timeit.html#timeit.Timer.timeit ) कहा जाता है ।
एलिस पेरिवल

7

सूची प्रदर्शन:

>>> import timeit
>>> timeit.timeit(stmt='10**6 in a', setup='a = range(10**6)', number=100000)
0.008128150348026608

प्रदर्शन सेट करें:

>>> timeit.timeit(stmt='10**6 in a', setup='a = set(range(10**6))', number=100000)
0.005674857488571661

आप Tuples पर विचार करना चाह सकते हैं क्योंकि वे सूचियों के समान हैं लेकिन उन्हें संशोधित नहीं किया जा सकता है। वे थोड़ी कम मेमोरी लेते हैं और एक्सेस करने में तेज़ होते हैं। वे लचीले नहीं हैं, लेकिन सूचियों की तुलना में अधिक कुशल हैं। उनका सामान्य उपयोग शब्दकोश कुंजी के रूप में सेवा करना है।

सेट भी अनुक्रम संरचनाएं हैं लेकिन सूचियों और टुपल्स के दो अंतरों के साथ। हालाँकि सेट में एक आदेश होता है, लेकिन यह क्रम मनमाना होता है और प्रोग्रामर के नियंत्रण में नहीं होता है। दूसरा अंतर यह है कि एक सेट में तत्व अद्वितीय होने चाहिए।

setपरिभाषा से। [ अजगर | विकी ]।

>>> x = set([1, 1, 2, 2, 3, 3])
>>> x
{1, 2, 3}

4
सबसे पहले, आपको setबिल्ट-इन प्रकार के लिंक ( docs.python.org/2/library/stdtypes.html#set ) से अपडेट करना चाहिए, न कि डिप्रेस्डsets लाइब्रेरी। दूसरा, "सेट भी अनुक्रम संरचनाएं हैं", अंतर्निहित प्रकार लिंक से निम्नलिखित पढ़ें: "एक अनियंत्रित संग्रह होने के नाते, सेट तत्व स्थिति या सम्मिलन के आदेश को रिकॉर्ड नहीं करते हैं। तदनुसार, सेट अनुक्रमण, टुकड़ा करने की क्रिया, या अन्य का समर्थन नहीं करते हैं। अनुक्रम जैसा व्यवहार। "
Seaux

7
rangeनहीं है listrangeकस्टम __contains__जादू पद्धति के साथ एक विशेष वर्ग है ।
Ryne वांग

@RyneWang यह सच है, लेकिन केवल पायथन 3 के लिए। Python2 रेंज में एक सामान्य सूची मिलती है (इसीलिए इसमें भयानक चीजें मौजूद हैं xrange)
Manoel Vilela

7

Setनिकट के कारण होने वाली जीत में 'चेक' शामिल हैं: https://en.wikipedia.org/wiki/Hash_table

सूची कार्यान्वयन: आमतौर पर एक सरणी, धातु के करीब निम्न स्तर, पुनरावृत्ति के लिए अच्छा और तत्व सूचकांक द्वारा यादृच्छिक अभिगम।

सेट कार्यान्वयन: https://en.wikipedia.org/wiki/Hash_table , यह एक सूची पर पुनरावृत्त नहीं करता है, लेकिन कुंजी से हैश की गणना करके तत्व को खोजता है , इसलिए यह प्रमुख तत्वों की प्रकृति और हैश पर निर्भर करता है समारोह। जैसा तानाशाही के लिए उपयोग किया जाता है, वैसा ही। मुझे संदेह है कि listअगर आपके पास बहुत कम तत्व हैं (<5), तो बड़ा तत्व setएक चेक की जांच के लिए बेहतर प्रदर्शन करेगा। यह तत्व जोड़ने और हटाने के लिए भी तेज है। यह भी हमेशा ध्यान रखें कि एक सेट के निर्माण में एक लागत होती है!

नोट : यदि listपहले से ही हल किया गया है, तो खोज करना listकाफी तेज हो सकता है, लेकिन सामान्य मामलों के setलिए चेक के लिए तेजी से और सरल है।


8
धातु के करीब? अजगर के संदर्भ में भी इसका क्या मतलब है? एक सेट की तुलना में धातु के करीब एक सूची कैसे है?
मुर्गागंज

@roganjosh, python अभी भी एक मशीन पर चलता है और कुछ कार्यान्वयन जैसे कि 'array' के रूप में सूची में हार्डवेयर के अच्छे होने के करीब हैं: stackoverflow.com/questions/176011/… , लेकिन यह हमेशा इस बात पर निर्भर करता है कि आप क्या हासिल करना चाहते हैं, यह कार्यान्वयन के बारे में थोड़ा जानना अच्छा है, न कि केवल अमूर्तता।
क्रिस्टोफ रूसो

2

tl; डॉ

डेटा संरचनाएं (डीएस) महत्वपूर्ण हैं, क्योंकि उनका उपयोग डेटा पर संचालन करने के लिए किया जाता है, जो मूल रूप से इसका तात्पर्य है: कुछ इनपुट लें , इसे संसाधित करें और आउटपुट वापस दें

कुछ डेटा संरचनाएं कुछ विशेष मामलों में दूसरों की तुलना में अधिक उपयोगी होती हैं। इसलिए, यह पूछना काफी अनुचित है कि कौन सा (डीएस) अधिक कुशल / शीघ्र है। यह पूछने जैसा है कि चाकू और कांटे के बीच कौन सा उपकरण अधिक कुशल है। मेरा मतलब है कि सब स्थिति पर निर्भर करता है।

सूचियाँ

एक सूची परस्पर अनुक्रम है , जिसका उपयोग आमतौर पर सजातीय वस्तुओं के संग्रह को संग्रहीत करने के लिए किया जाता है

सेट

एक सेट ऑब्जेक्ट अलग-अलग धोने योग्य वस्तुओं का एक अनियोजित संग्रह है । इसका उपयोग आमतौर पर सदस्यता का परीक्षण करने, एक अनुक्रम से डुप्लिकेट को हटाने, और गणितीय संचालन जैसे कि चौराहे, संघ, अंतर और सममित अंतर की गणना करने के लिए किया जाता है।

प्रयोग

कुछ उत्तरों से, यह स्पष्ट है कि मूल्यों की पुनरावृति करते समय एक सूची सेट की तुलना में काफी तेज है। दूसरी ओर, एक सेट सूची की तुलना में तेज़ होता है जब यह जांचता है कि कोई आइटम उसके भीतर समाहित है या नहीं। इसलिए, आप केवल एक ही बात कह सकते हैं कि कुछ विशेष कार्यों के लिए एक सूची सेट से बेहतर है और इसके विपरीत।


2

CPython के साथ जाँच करते समय मुझे परिणामों में दिलचस्पी थी, अगर मूल्य शाब्दिक की एक छोटी संख्या में से एक है। setपायथन 3 बनाम में जीत tuple, listऔर or:

from timeit import timeit

def in_test1():
  for i in range(1000):
    if i in (314, 628):
      pass

def in_test2():
  for i in range(1000):
    if i in [314, 628]:
      pass

def in_test3():
  for i in range(1000):
    if i in {314, 628}:
      pass

def in_test4():
  for i in range(1000):
    if i == 314 or i == 628:
      pass

print("tuple")
print(timeit("in_test1()", setup="from __main__ import in_test1", number=100000))
print("list")
print(timeit("in_test2()", setup="from __main__ import in_test2", number=100000))
print("set")
print(timeit("in_test3()", setup="from __main__ import in_test3", number=100000))
print("or")
print(timeit("in_test4()", setup="from __main__ import in_test4", number=100000))

आउटपुट:

tuple
4.735646052286029
list
4.7308746771886945
set
3.5755991376936436
or
4.687681658193469

3 से 5 लीटर के लिए, setअभी भी एक व्यापक अंतर से जीतता है, और orसबसे धीमा हो जाता है।

पायथन 2 में, setहमेशा सबसे धीमा होता है। or2 से 3 शाब्दिक के लिए सबसे तेजी से है, और tupleऔर listतेजी से 4 या अधिक शाब्दिक के साथ हैं। मैं tupleबनाम की गति को भेद नहीं सका list

जब परीक्षण के मूल्यों को लूप के भीतर शाब्दिक बनाने के बजाय एक वैश्विक चर में कैश किया गया था, तो setहर बार जीता, यहां तक ​​कि पायथन 2 में भी।

ये परिणाम कोर i7 पर 64-बिट CPython पर लागू होते हैं।


0

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


1
वास्तव में, सेट का उपयोग करने के लिए और टुपल का उपयोग करने के बीच उचित अंतर वास्तव में अत्यधिक महत्व का है। जब तक मैं एक निम्न-स्तरीय API स्क्रिप्ट नहीं कर रहा हूं, मुझे शामिल मेमोरी ओवरहेड्स, पैरों के निशान के बारे में चिंतित नहीं होना चाहिए।

0
from datetime import datetime
listA = range(10000000)
setA = set(listA)
tupA = tuple(listA)
#Source Code

def calc(data, type):
start = datetime.now()
if data in type:
print ""
end = datetime.now()
print end-start

calc(9999, listA)
calc(9999, tupA)
calc(9999, setA)

सभी 3 के लिए 10 पुनरावृत्तियों की तुलना के बाद आउटपुट: तुलना


0

सेट अधिक तेज़ होते हैं, आपको सेट के साथ अधिक फ़ंक्शंस मिलते हैं, जैसे कि दो सेट आपके पास हैं:

set1 = {"Harry Potter", "James Bond", "Iron Man"}
set2 = {"Captain America", "Black Widow", "Hulk", "Harry Potter", "James Bond"}

हम आसानी से दो सेटों में शामिल हो सकते हैं:

set3 = set1.union(set2)

जानें क्या है दोनों में कॉमन:

set3 = set1.intersection(set2)

जानें क्या है दोनों में अलग:

set3 = set1.difference(set2)

और भी बहुत कुछ! बस उन्हें बाहर की कोशिश करो, वे मज़ेदार हैं! इसके अलावा अगर आपको 2 सूची के भीतर अलग-अलग मानों पर काम करना है या 2 सूचियों के भीतर सामान्य मूल्य हैं, तो मैं आपकी सूचियों को सेट में बदलना पसंद करता हूं, और कई प्रोग्रामर उस तरह से करते हैं। आशा है कि यह आपकी मदद करता है :-)

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