पायथन: टेबल अप लुक के लिए सूची बनाम डिक्ट


169

मैं, 10million के बारे में मूल्यों है कि मैं मेज ऊपर देखो किसी प्रकार में डाल करने की जरूरत है तो मैं सोच रहा था जो अधिक कुशल एक होगा सूची या dict ?

मुझे पता है कि आप दोनों के लिए कुछ ऐसा कर सकते हैं:

if something in dict_of_stuff:
    pass

तथा

if something in list_of_stuff:
    pass

मेरा विचार है कि हुकुम तेज और अधिक कुशल होगा।

आपकी सहायता के लिए धन्यवाद।

संपादित 1
मैं क्या करने की कोशिश कर रहा हूँ पर थोड़ा अधिक जानकारी। यूलर प्रॉब्लम 92 । मैं यह देखने के लिए एक तालिका बना रहा हूं कि क्या गणना के लिए तैयार मूल्य की गणना की गई है।

EDIT 2
देखने के लिए दक्षता।

EDIT 3
मान के साथ कोई मान नहीं है ... तो क्या एक सेट बेहतर होगा?


1
क्या के संदर्भ में दक्षता? सम्मिलित करें? देखो? मेमोरी की खपत? क्या आप मूल्य के शुद्ध अस्तित्व के लिए जाँच कर रहे हैं, या इसके साथ कोई मेटाडेटा जुड़ा हुआ है?
तुरुपो

एक साइड नोट के रूप में, आपको उस विशिष्ट समस्या के लिए 10 मिलियन सूची या तानाशाही की आवश्यकता नहीं है, लेकिन बहुत छोटा है।
sfotiadis

जवाबों:


222

गति

सूचियों में लुकअप O (n) हैं, शब्दकोशों में लुकअप को डेटा संरचना में वस्तुओं की संख्या के संबंध में O (1) परिशोधन किया जाता है। यदि आपको मूल्यों को संबद्ध करने की आवश्यकता नहीं है, तो सेट का उपयोग करें।

स्मृति

दोनों शब्दकोश और सेट हैशिंग का उपयोग करते हैं और वे केवल मेमोरी स्टोरेज की तुलना में बहुत अधिक मेमोरी का उपयोग करते हैं। ब्यूटीफुल कोड में एएम कुचलिंग के अनुसार , कार्यान्वयन हैश 2/3 को पूर्ण रखने की कोशिश करता है, इसलिए आप कुछ मेमोरी बर्बाद कर सकते हैं।

यदि आप मक्खी पर नई प्रविष्टियाँ नहीं जोड़ते हैं (जो आप करते हैं, आपके अद्यतन प्रश्न के आधार पर), तो सूची को क्रमबद्ध करना और द्विआधारी खोज का उपयोग करना सार्थक हो सकता है। यह ओ (लॉग एन) है, और तारों के लिए धीमा होने की संभावना है, उन वस्तुओं के लिए असंभव है जिनके पास प्राकृतिक ऑर्डर नहीं है।


6
हां, लेकिन यदि सामग्री कभी नहीं बदलती है तो यह एक बार की कार्रवाई है। बाइनरी खोज ओ (लॉग एन) है।
टॉर्स्टन मारेक

1
@ जॉन फोहे: हैश तालिका में चींटियों को संग्रहित नहीं किया जाता है, केवल पॉइंटर, यानी हौ के पास 40 मीटर होते हैं (अच्छी तरह से, वास्तव में जब उनमें से बहुत छोटे होते हैं) और हैश तालिका के लिए 60 मीटर। मैं मानता हूं कि यह आजकल की समस्या नहीं है, फिर भी इसे ध्यान में रखना सार्थक है।
टॉर्स्टन मारेक

2
यह एक पुराना सवाल है, लेकिन मुझे लगता है कि बहुत बड़े सेट / डक्ट के लिए O (1) सही नहीं है। Wiki.python.org/moin/TimeComplexity के अनुसार सबसे खराब स्थिति O (n) है। मुझे लगता है कि यह आंतरिक हैशिंग कार्यान्वयन पर निर्भर करता है कि किस समय ओ (1) से औसत समय निकलता है और ओ (एन) पर परिवर्तित होना शुरू होता है। जब तक आपको इष्टतम सेट आकार प्राप्त करने की आवश्यकता होती है, तब तक कुछ आसानी से पहचाने जाने योग्य विशेषता (जैसे पहले अंक के मूल्य, फिर दूसरे, तीसरे, आदि) के आधार पर वैश्विक सेटों को कंपार्टमेंट करके, लुकअप प्रदर्शन में मदद कर सकते हैं। ।
निसान।

3
@TorstenMarek यह मुझे भ्रमित करता है। से यह पेज , सूची देखने हे (1) और dict देखने O (n) है, जो आपने कहा है के विपरीत है। क्या मैं गलतफहमी हूँ?
temporary_user_name

3
@Aerovistae मुझे लगता है कि आप उस पृष्ठ पर जानकारी को गलत समझते हैं। सूची के तहत, मुझे "x in s" (लुकअप) के लिए O (n) दिखाई देता है। यह ओ (1) औसत मामले के रूप में सेट और तानाशाह को भी दिखाता है।
डेनिस

45

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


संपादित करें: आपके नए प्रश्न के लिए, हाँ, एक सेट बेहतर होगा। बस 2 सेट बनाएं, 1 में समाप्त होने वाले दृश्यों के लिए एक और 89 में समाप्त होने वाले अनुक्रमों के लिए। मैंने सेट्स का उपयोग करके इस समस्या को सफलतापूर्वक हल किया है।



31

मैंने कुछ बेंचमार्किंग की और यह पता चला कि तानाशाही लिस्ट से तेज है और बड़े डेटा सेटों के लिए सेट है, लियोन पर i7 CPU पर अजगर 2.7.3 रन कर रहा है:

  • python -mtimeit -s 'd=range(10**7)' '5*10**6 in d'

    10 लूप, सर्वश्रेष्ठ 3: 64.2 मिसे प्रति लूप

  • python -mtimeit -s 'd=dict.fromkeys(range(10**7))' '5*10**6 in d'

    10000000 लूप, 3 का सर्वश्रेष्ठ: 0.0759 प्रति लूप

  • python -mtimeit -s 'from sets import Set; d=Set(range(10**7))' '5*10**6 in d'

    1000000 लूप्स, सर्वश्रेष्ठ 3: 0.262 प्रति लूप के हिसाब से

जैसा कि आप देख सकते हैं, तानाशाही सूची की तुलना में काफी तेज है और सेट की तुलना में लगभग 3 गुना तेज है। कुछ अनुप्रयोगों में आप अभी भी इसकी सुंदरता के लिए सेट चुनना चाह सकते हैं, हालांकि। और अगर डेटा सेट वास्तव में छोटे हैं (<1000 तत्व) सूचियाँ बहुत अच्छा प्रदर्शन करती हैं।


यह बिल्कुल विपरीत नहीं होना चाहिए? सूची: 10 * 64.2 * 1000 = 642000 usec, तानाशाह: 10000000 * 0.0759 = 759000 usec और सेट: 1000000 * 0.262 = 262000 usec ... तो सेट सबसे तेज़ होते हैं, इसके बाद सूची में और आपके उदाहरण पर अंतिम के रूप में तानाशाही होती है। या क्या मैं कुछ न कुछ भूल रहा हूं?
andzep

1
... लेकिन यहाँ मेरे लिए सवाल यह है: यह समय वास्तव में क्या माप रहा है? किसी दिए गए सूची के लिए एक्सेस समय नहीं, तानाशाही या सेट, लेकिन बहुत अधिक, सूची बनाने के लिए समय और लूप , एक सेट और अंत में एक मूल्य खोजने और उपयोग करने के लिए। तो, क्या इसका सवाल बिल्कुल भी नहीं है? ... यह दिलचस्प है, हालांकि है ...
andzep

8
@andzep, आप गलत हैं, -sविकल्प timeitपर्यावरण को सेटअप करना है, अर्थात यह कुल समय में नहीं गिना जाता है। -sविकल्प केवल एक बार चलाया जाता है। पायथन 3.3 पर, मुझे ये परिणाम मिले: जीन (रेंज) -> 0.229 usec, सूची -> 157 मिसेक, तानाशाह -> 0.0806 usec, सेट -> 0.0807 usec। सेट और तानाशाही प्रदर्शन समान है। हालांकि डिक्ट को सेट करने की तुलना में थोड़ा अधिक समय लगता है (कुल समय 13.580 वी। 11.803s)
स्लीब्लांक

1
क्यों नहीं बिलिन सेट का उपयोग करें? मैं वास्तव में सेट के साथ बहुत खराब परिणाम प्राप्त करता हूं। सेट () से बिल्टिन सेट () के साथ
थॉमस गयोट-सायननेस्ट

2
@ ThomasGuyot-Sionnest सेट में बनाया गया था अजगर 2.4 में पेश किया गया था, इसलिए मुझे यकीन नहीं है कि मैंने अपने प्रस्तावित समाधान में इसका उपयोग क्यों नहीं किया। मुझे python -mtimeit -s "d=set(range(10**7))" "5*10**6 in d"पायथन 3.6.0 (10000000 लूप, 3 का सबसे अच्छा: 0.0608 usec प्रति लूप) का उपयोग करने के साथ अच्छा प्रदर्शन मिलता है , मोटे तौर पर उसी तरह का जैसा कि बेंचमार्क है इसलिए आपकी टिप्पणी के लिए धन्यवाद।
ईरीएफ89

6

आप एक तानाशाही चाहते हैं।

पायथन में (अनसोल्ड) सूचियों के लिए, "इन" ऑपरेशन के लिए ओ (एन) समय की आवश्यकता होती है --- अच्छा नहीं जब आपके पास बड़ी मात्रा में डेटा हो। दूसरी ओर, एक तानाशाह, एक हैश टेबल है, जिससे आप O (1) लुकअप टाइम की उम्मीद कर सकते हैं।

जैसा कि अन्य ने उल्लेख किया है, आप इसके बजाय एक सेट (विशेष प्रकार का तानाशाही) चुन सकते हैं, यदि आपके पास कुंजी / मूल्य जोड़े के बजाय केवल कुंजी है।

सम्बंधित:

  • पायथन विकी : पायथन कंटेनर संचालन की समय जटिलता के बारे में जानकारी।
  • SO : अजगर कंटेनर संचालन समय और मेमोरी जटिलताएं

1
यहां तक ​​कि क्रमबद्ध सूचियों के लिए, "इन" O (n) है।

2
एक लिंक की गई सूची के लिए, पायथन में हां --- लेकिन "सूचियां" हैं, जो ज्यादातर लोग वैक्टर कहते हैं, जो ओ (1) में अनुक्रमित पहुंच प्रदान करते हैं और जब सॉर्ट किया जाता है तो ओ (लॉग एन) में एक खोज ऑपरेशन होता है।
zweiterlinde

क्या आप यह कह रहे हैं कि inएक सॉर्ट की गई सूची पर लागू किया गया ऑपरेटर अनसेन्डेड (एक रैंडम वैल्यू की खोज के लिए) पर लागू होने से बेहतर प्रदर्शन करता है? (मुझे नहीं लगता कि वे वैक्टर के रूप में आंतरिक रूप से कार्यान्वित किए जाते हैं या एक लिंक्ड-लिस्ट में नोड्स प्रासंगिक हैं।)
मार्टिअन

4

अगर डेटा यूनिक सेट () सबसे अधिक कुशल होगा, लेकिन दो - तानाशाही (जिसमें विशिष्टता की भी आवश्यकता है, उफ़ :)


मुझे एहसास हुआ कि जब मैंने अपना जवाब% पोस्ट किया था)
साइलेंटगॉस्ट

2
@SilentGhost अगर जवाब गलत है, तो इसे क्यों नहीं हटाया जा रहा है? upvotes के लिए बहुत बुरा है, लेकिन वह (अच्छी तरह से, होता हुआ )
जीन फ़्राँस्वा Fabre

3

@ EriF89 दिखाने के लिए परीक्षणों के एक नए सेट के रूप में इन सभी वर्षों के बाद भी सही है:

$ python -m timeit -s "l={k:k for k in xrange(5000)}"    "[i for i in xrange(10000) if i in l]"
1000 loops, best of 3: 1.84 msec per loop
$ python -m timeit -s "l=[k for k in xrange(5000)]"    "[i for i in xrange(10000) if i in l]"
10 loops, best of 3: 573 msec per loop
$ python -m timeit -s "l=tuple([k for k in xrange(5000)])"    "[i for i in xrange(10000) if i in l]"
10 loops, best of 3: 587 msec per loop
$ python -m timeit -s "l=set([k for k in xrange(5000)])"    "[i for i in xrange(10000) if i in l]"
1000 loops, best of 3: 1.88 msec per loop

यहां हम कुछ उपयोग मामलों में tupleतुलना करने वाले lists(और कम मेमोरी का उपयोग करने वाले) तेजी से ज्ञात होते हैं । लुकअप टेबल के मामले में, tupleमेला बेहतर नहीं रहा।

दोनों dictऔरset बहुत अच्छा प्रदर्शन किया। यह विशिष्टता के बारे में @SententGhost उत्तर में बांधने के लिए एक दिलचस्प बिंदु लाता है: यदि ओपी के पास डेटा सेट में 10M मान हैं, और यह अज्ञात है अगर उनमें डुप्लिकेट हैं, तो यह समानांतर में अपने तत्वों का एक सेट / तानाशाही रखने लायक होगा। वास्तविक डेटा सेट के साथ, और उस सेट / अस्तित्व में अस्तित्व के लिए परीक्षण। यह संभव है कि 10M डेटा बिंदुओं में केवल 10 अद्वितीय मूल्य हों, जो कि खोज करने के लिए बहुत छोटा स्थान है!

Dicts के बारे में साइलेंटगॉस्ट की गलती वास्तव में रोशन है क्योंकि एक डुप्लिकेट डेटा (मानों में) को एक nonduplicated सेट (कुंजियों) में सहसंबंधित करने के लिए एक तानाशाह का उपयोग कर सकता है, और इस प्रकार सभी डेटा रखने के लिए एक डेटा ऑब्जेक्ट रखता है, फिर भी एक लुकअप तालिका के रूप में तेज़ है। उदाहरण के लिए, एक प्रमुख कुंजी मूल्य को देखा जा सकता है, और मूल्य एक काल्पनिक सूची में सूचकांकों की एक सूची हो सकती है जहां यह मूल्य हुआ था।

उदाहरण के लिए, यदि स्रोत डेटा सूची को खोजा जाना था l=[1,2,3,1,2,1,4], तो इसे इस श्रुत के साथ प्रतिस्थापित करके खोज और मेमोरी दोनों के लिए अनुकूलित किया जा सकता है:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> l=[1,2,3,1,2,1,4]
>>> for i, e in enumerate(l):
...     d[e].append(i)
>>> d
defaultdict(<class 'list'>, {1: [0, 3, 5], 2: [1, 4], 3: [2], 4: [6]})

इस आदेश के साथ, कोई भी जान सकता है:

  1. यदि मान मूल डेटासेट में था (यानी 2 in dरिटर्न True)
  2. कहाँ मूल्य मूल डाटासेट में था (यानी d[2]सूचकांकों की सूची जहां डाटा मूल डेटा सूची में पाया गया था रिटर्न: [1, 4])

आपके अंतिम पैराग्राफ के लिए, जबकि यह समझ में आता है कि यह पढ़ना अच्छा है (और शायद समझ में आसान है) उस वास्तविक कोड को देखने के लिए जिसे आप समझाने की कोशिश कर रहे हैं।
केसर

0

आपको वास्तव में तालिका में 10 मिलियन मूल्यों को संग्रहीत करने की आवश्यकता नहीं है, इसलिए यह किसी भी तरह से बड़ी बात नहीं है।

संकेत: इस बारे में सोचें कि वर्गों के संचालन के पहले योग के बाद आपका परिणाम कितना बड़ा हो सकता है। सबसे बड़ा संभावित परिणाम 10 मिलियन से बहुत छोटा होगा ...

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