2012-05-23 15 views
29

इस समय मेरे पास 1million integers का list है, और मैं 2000 integer एस की ब्लैकलिस्ट के विरुद्ध प्रत्येक integer की जांच करता हूं। इसमें लगभग 2 मिनट लग रहे हैं।पूर्णांक की बड़ी सूची को पूर्णांक की सूची में तुलना करने के लिए सबसे कुशल तरीका क्या है?

for(int i = 0; i< MillionIntegerList.Length ; i++) 
{ 
    for(int blacklisted = 0; blacklisted < TwoThousandIntegerList.Length ; blacklisted++) 
     if(i==blacklisted) 
      i = 0; //Zero is a sentinel value 
} 

यह 2,000,000,000 पुनरावृत्तियों (लूप) को पूरी तरह से बनाता है। क्या मैं बेहतर नहीं देख रहा हूं? धन्यवाद

+2

या तो सूची क्रमबद्ध है? –

+0

असल में मिलियन पूर्णांक सूची को हल किया गया है, ब्लैकलिस्टेड – theIrishUser

+0

नहीं है लेकिन ब्लैकलिस्ट को सॉर्ट करने की लागत कुछ भी नहीं है जो आप करना चाहते हैं। – Thomash

उत्तर

51

अब तीन विकल्प - पहले दो अधिक सामान्य हैं, जिसमें वे MillionIntegerList पर भरोसा नहीं करते हैं (जिसे मूल रूप से निर्दिष्ट नहीं किया गया था)। तीसरा मामला उस मामले में बेहतर है जहां बड़ी सूची पहले ही क्रमबद्ध है।

विकल्प 1

हाँ, वहाँ निश्चित रूप से इसे करने का एक बेहतर तरीका है, LINQ का उपयोग कर रहा है:

var common = MillionIntegerList.Intersect(TwoThousandIntegerList).ToList(); 

कि आंतरिक रूप से एक HashSet<int>TwoThousandIntegerList के माध्यम से बनाया का उपयोग करेगा, तो ऊपर के प्रत्येक तत्व देखो MillionIntegerList इसके भीतर - जो हर बार TwoThousandIntegerList के माध्यम से जाने से कहीं अधिक कुशल होगा।

आप केवल गैर काली सूची में डाल लोगों को चाहते हैं, आप की जरूरत है:

var valid = MillionIntegerList.Except(TwoThousandIntegerList).ToList(); 

ध्यान दें कि यदि आप केवल एक बार परिणामों पर पुनरावृति करने की जरूरत है, तो आप ToList कॉल निकाल देना चाहिए - मैं इसे करने के लिए शामिल किया है परिणामों को पूरा करें ताकि उन्हें कई बार सस्ता जांच की जा सके। यदि आप अभी पुनरावृत्त कर रहे हैं, तो Intersect या Except का वापसी मूल्य केवल स्ट्रीम परिणाम देगा, जिससे स्मृति उपयोग के मामले में यह बहुत सस्ता हो जाएगा।

विकल्प 2

आप वस्तुओं को LINQ के कार्यान्वयन के विवरण पर भरोसा करने के लिए नहीं करना चाहते हैं लेकिन आप अभी भी एक हैश आधारित दृष्टिकोण चाहते हैं:

var hashSet = new HashSet<int>(TwoThousandIntegerList); 
hashSet.IntersectWith(MillionIntegerList); 
// Now use hashSet 

विकल्प 3

इस तथ्य का उपयोग करने का दृष्टिकोण कि बड़ी सूची सॉर्ट की गई है, निश्चित रूप से उपयोगी होगी।

मान लिया जाये कि आप नहीं पहले के साथ-साथ काली सूची में डाल सूची छँटाई बात नहीं, आप एक स्ट्रीमिंग (और सामान्य प्रयोजन) कार्यान्वयन इस तरह (untested) लिख सकता है:

// Note: to use this, you'd need to make sure that *both* sequences are sorted. 
// You could either sort TwoThousandIntegerList in place, or use LINQ's OrderBy 
// method. 

public IEnumerable<T> SortedIntersect<T>(this IEnumerable<T> first, 
    IEnumerable<T> second) where T : IComparable<T> 
{ 
    using (var firstIterator = first.GetEnumerator()) 
    { 
     if (!firstIterator.MoveNext()) 
     { 
      yield break; 
     } 

     using (var secondIterator = second.GetEnumerator()) 
     { 
      if (!secondIterator.MoveNext()) 
      { 
       yield break; 
      } 
      T firstValue = firstIterator.Current; 
      T secondValue = secondIterator.Current; 

      while (true) 
      { 
       int comparison = firstValue.CompareTo(secondValue); 
       if (comparison == 0) // firstValue == secondValue 
       { 
        yield return firstValue; 
       } 
       else if (comparison < 0) // firstValue < secondValue 
       { 
        if (!firstIterator.MoveNext()) 
        { 
         yield break; 
        } 
        firstValue = firstIterator.Current; 
       } 
       else // firstValue > secondValue 
       { 
        if (!secondIterator.MoveNext()) 
        { 
         yield break; 
        } 
        secondValue = secondIterator.Current; 
       } 
      }     
     } 
    } 
} 

(आप एक IComparer<T> अगर आप समय लग सकता है टी पर तुलनीय होने के बजाय चाहता था।)

+0

बहुत धन्यवाद जॉन स्कीट – theIrishUser

+0

मान लीजिए कि मिलियनइंटर लिस्ट में दोThousandIntegerList की तुलना में कई और सदस्य हैं, क्या यह इस तरह से तेज़ होगा? 'var common = twoThousandIntegerList.Intersect (MillionIntegerList) .ToList();' –

+2

@ ErenErsönmez: नहीं, क्योंकि यह * बड़े * सेट का हैशसेट बनाएगा। एमएसडीएन में प्रलेखन वास्तव में गलत है जब यह इंटरसेक्ट की बात आती है - http://msmvps.com/blogs/jon_skeet/archive/2010/12/30/reimplementing-linq-to-objects-part-16-intersect-and- अधिक जानकारी के लिए build-fiddling.aspx। –

1

अवरुद्ध सूची के लिए हैशसेट का उपयोग करें।

foreach(integer i in MillionIntegerList) 
{ 
     //check if blockedlist contains i 
     //do what ever you like. 
} 
-2

उपयोग सूची के लिए Except विधि। यह

17

काम करेगा क्योंकि बड़ी सूची क्रमबद्ध है। आपको छोटी सूची (बहुत तेज़) क्रमबद्ध करके और फिर रैखिक विलय करके सर्वोत्तम परिणाम मिल सकते हैं। आपको केवल एक बार बड़ी (और छोटी) सूची में प्रत्येक आइटम को देखने की आवश्यकता होगी, और पृष्ठभूमि में हैशटेबल को बनाने की आवश्यकता नहीं होगी।

यह करने के तरीके के बारे में एक विचार के लिए MergeSort के merge function भाग देखें।

+0

आशा है कि आपको कोई फर्क नहीं पड़ता - मैंने अपने जवाब में इस हिस्से का एक सामान्य कार्यान्वयन जोड़ा है। द्विआधारी खोज का उल्लेख करने के लिए –

3

आपके दृष्टिकोण के लिए ओ (एन * एन) समय की आवश्यकता है। इन अनुकूलन पर विचार करें:

  • 1)

    अपने पूर्णांकों बहुत बड़ी है, आप bool की सरणी का उपयोग कर सकते नहीं कर रहे हैं (उदाहरण के लिए अगर सबसे बड़ी संभव पूर्णांक है 1000000 उपयोग bool [] ख = नए bool [ 1000000])। अब ब्लैकलिस्ट का उपयोग करने के लिए संख्या संख्या को जोड़ने के लिए बी [के] = सत्य। चेक तुच्छ है। यह ओ (एन) में काम करता है। तुम भी BitArray

  • 2 उपयोग कर सकते हैं)

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

+0

+1। - यदि बड़ी सूची पहले से ही क्रमबद्ध है और इसके तत्वों को सस्ता रूप से इंडेक्स (जैसे सरणी में) तक पहुंचा जा सकता है, तो बाइनरी सर्च एल्गोरिदम इसे लागू करने के लिए लगभग छोटा है, जिससे ओ (एन * लॉग (एम)) की लागत कम हो जाती है सभी डेटा को एक पेड़ या हैशपैप जैसी अन्य डेटा संरचना में कॉपी करने के लिए। – JimmyB

+0

हां। यदि भविष्य में "ब्लैकलिस्ट" नहीं बदला जाएगा, तो इसे सॉर्ट किया जा सकता है और पेड़ों जैसे किसी भी अतिरिक्त संरचना के बिना बाइनरी खोज का उपयोग करके आइटम मिल सकते हैं। .NET को पहले से सॉर्ट करने के लिए कार्यान्वयन है (Array.Sort और list.Sort) और बाइनरी खोज (Array.BinarySearch और list.BinarySearch) –

1

मुझे लगता है कि सबसे अच्छा समाधान एक Bloom filter उपयोग करने के लिए है और यह मामला ब्लूम फिल्टर का कहना है एक तत्व ब्लैकलिस्ट में हो सकता है, बस जांचें कि क्या गलत पॉजिटिव नहीं है (यदि ब्लैकलिस्ट सॉर्ट किया गया है तो ओ (लॉग (एन)) में किया जा सकता है)। यह समाधान समय कुशल है और लगभग कोई अतिरिक्त स्थान नहीं उपयोग करता है जो इसे हैशसेट का उपयोग करने से कहीं बेहतर बनाता है।

यह वह समाधान है जो Google क्रोम में ब्लैकलिस्ट के लिए उपयोग करता है।

+3

मुझे अपना डाउनवोट समझाएं। 1) यह समस्या को हल नहीं करता है (झूठी सकारात्मक) 2) कहीं भी आप इसका उल्लेख नहीं करते हैं और यह वास्तविक समस्या का समाधान नहीं करता है 3) क्रोम वास्तव में केवल ब्लैकलिस्ट के लिए एक वेब सेवा जांचने का निर्णय लेने के लिए फ़िल्टर का उपयोग करता है। – ex0du5

+0

1) झूठी सकारात्मक बहुत असामान्य हैं इसलिए यह कोई समस्या नहीं होनी चाहिए। – Thomash

+0

2) वास्तव में मैंने ब्लॉम फ़िल्टर के बारे में सबकुछ समझाया नहीं है, लेकिन मुझे लगता है कि कोई भी लिंक पर क्लिक कर सकता है और विकिपीडिया लेख पढ़ सकता है। – Thomash

1

लंबी सूची में बाइनरी खोज करने के बारे में, क्योंकि यह सॉर्ट किया गया है।

foreach(integer blacklisted in TwoThousandIntegerList) 
{ 
    integer i = MillionIntegerList.binarySearch(blacklisted) 
    if(i==blacklisted){ 
      //Do your stuff 
    } 
} 

यह समाधान केवल लागत हे (एम लॉग एन) समय है, जहां मीटर छोटी सूची के आकार है और n लंबी सूची का आकार है। चेतावनी: यह समाधान मानता है कि MillionIntegerList में कोई डुप्लिकेट मान नहीं है।

यदि ऐसा नहीं है, तो आप दोहराने के बावजूद फिर से दोहरा सकते हैं क्योंकि उन्हें एक संगत ब्लॉक में झूठ बोलना चाहिए। इसके लिए, मुझे लगता है कि MillionInterList रिकॉर्ड की एक सूची है, प्रत्येक value और index के साथ।

foreach(integer blacklisted in TwoThousandIntegerList) 
{ 
    integer index = MillionIntegerList.binarySearch(blacklisted) 
    //Find the index of the first occurrence of blacklisted value 
    while(index > 0 && MillionIntegerList[index - 1].value == blacklisted){ 
      --index; 
    } 
    while(MillionIntegerList[index].value == blacklisted){ 
      //Do your stuff 
      ++index; 
    } 
} 

यह समाधान लागत हे (एम लॉग n + mk) जहां कश्मीरMillionInterList में पाया काली सूची में डाल पूर्णांक प्रति डुप्लिकेट की औसत संख्या है।

संबंधित मुद्दे