मुझे HashSet <T> प्रकार का उपयोग कब करना चाहिए?


134

मैं HashSet<T>प्रकार की खोज कर रहा हूं, लेकिन मुझे समझ नहीं आ रहा है कि यह संग्रह में कहां खड़ा है।

क्या कोई इसे बदलने के लिए उपयोग कर सकता है List<T>? मैं HashSet<T>बेहतर होने के प्रदर्शन की कल्पना करता हूं , लेकिन मैं इसके तत्वों की व्यक्तिगत पहुंच नहीं देख सकता।

क्या यह केवल गणना के लिए है?

जवाबों:


228

HashSet<T>नाम के बारे में महत्वपूर्ण बात वहीं है: यह एक सेट है । केवल एक ही चीज़ जो आप एक सेट के साथ कर सकते हैं वह यह है कि इसके सदस्य क्या हैं, और यह जाँचने के लिए कि कोई आइटम सदस्य है या नहीं।

यह पूछने पर कि क्या आप एकल तत्व (जैसे set[45]) को पुनः प्राप्त कर सकते हैं , सेट की अवधारणा को गलत समझ रहा है। सेट के 45 वें तत्व जैसी कोई चीज नहीं है। एक सेट में आइटम का कोई आदेश नहीं है। {1, 2, 3} और {2, 3, 1} सेट हर मामले में समान हैं क्योंकि उनकी एक ही सदस्यता है, और सदस्यता वह सब मायने रखती है।

यह कुछ हद तक पुनरावृति के लिए खतरनाक है HashSet<T>क्योंकि ऐसा करने से सेट में वस्तुओं पर एक आदेश लागू होता है। यह आदेश वास्तव में सेट की संपत्ति नहीं है। आपको इस पर भरोसा नहीं करना चाहिए। यदि किसी संग्रह में वस्तुओं का ऑर्डर देना आपके लिए महत्वपूर्ण है, तो वह संग्रह सेट नहीं है।

सेट वास्तव में सीमित हैं और अद्वितीय सदस्यों के साथ हैं। दूसरी ओर, वे वास्तव में तेज़ हैं।


1
यह तथ्य कि ढांचा एक SortedSetडेटा संरचना प्रदान करता है या तो आप एक सेट की संपत्ति नहीं होने के आदेश के बारे में क्या कहते हैं - या विकास टीम से गलतफहमी की ओर इशारा करता है।
16

10
मुझे लगता है कि यह कहना अधिक सही है कि वस्तुओं के क्रम को HashSetपरिभाषित नहीं किया गया है, इसलिए पुनरावृत्त के आदेश पर निर्भर न रहें। यदि आप सेट को पुनरावृत्त करते हैं क्योंकि आप सेट में वस्तुओं के खिलाफ कुछ कर रहे हैं, तो यह खतरनाक नहीं है जब तक कि आप ऑर्डर से संबंधित किसी भी चीज पर भरोसा नहीं कर रहे हैं। ए SortedSetमें HashSet प्लस ऑर्डर के सभी गुण हैं , हालांकि SortedSetइससे प्राप्त नहीं होता है HashSet; rephrased, SortedSet अलग-अलग वस्तुओं का एक ऑर्डर किया गया संग्रह है
किट

110

यहां एक वास्तविक उदाहरण है जहां मैं एक का उपयोग करता हूं HashSet<string>:

UnrealScript फ़ाइलों के लिए मेरे सिंटैक्स हाइलाइटर का एक हिस्सा एक नई सुविधा है जो Doxygen- शैली टिप्पणियों पर प्रकाश डाला गया है । मैं बताने के लिए सक्षम होना चाहिए अगर एक @या \चाहे वह ग्रे (वैध) या लाल (अवैध) में दिखाने के लिए आदेश निर्धारित करने के लिए मान्य है। मेरे पास HashSet<string>सभी मान्य कमांड हैं, इसलिए जब भी मैंने @xxxलेसर में एक टोकन मारा, तो मैं validCommands.Contains(tokenText)अपने ओ (1) घनत्व जांच के रूप में उपयोग करता हूं। मैं वास्तव में मान्य कमांड के सेट में कमांड के अस्तित्व को छोड़कर किसी चीज की परवाह नहीं करता हूं । आइए मेरे सामने आने वाले विकल्पों को देखें:

  • Dictionary<string, ?>: मैं किस प्रकार के मूल्य के लिए उपयोग करता हूं? जब से मैं सिर्फ उपयोग करने जा रहा हूं, तब से मूल्य निरर्थक है ContainsKey। नोट: .NET 3.0 से पहले यह O (1) लुक्स के लिए एकमात्र विकल्प HashSet<T>था - 3.0 के लिए जोड़ा गया था और ISet<T>4.0 के लिए लागू किया गया था।
  • List<string>: यदि मैं सूची को क्रमबद्ध रखता हूं, तो मैं उपयोग कर सकता हूं BinarySearch, जो ओ (लॉग एन) है (ऊपर वर्णित इस तथ्य को नहीं देखें)। हालाँकि, चूंकि वैध आदेशों की मेरी सूची एक निश्चित सूची है जो कभी नहीं बदलती है, यह कभी भी बस से अधिक उपयुक्त नहीं होगी ...
  • string[]: फिर से, Array.BinarySearchO (लॉग एन) प्रदर्शन देता है। यदि सूची कम है, तो यह सबसे अच्छा प्रदर्शन विकल्प हो सकता है। यह हमेशा से कम जगह भूमि के ऊपर है HashSet, Dictionaryया List। इसके साथ भी BinarySearch, यह बड़े सेटों के लिए तेज़ नहीं है, लेकिन छोटे सेटों के लिए यह प्रयोग करने लायक होगा। मेरा हालांकि कई सौ आइटम हैं, इसलिए मैं इस पर से गुजरा।

24

एक HashSet<T>को लागू करता है ICollection<T>इंटरफ़ेस:

public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
    // Methods
    void Add(T item);
    void Clear();
    bool Contains(T item);
    void CopyTo(T[] array, int arrayIndex);
    bool Remove(T item);

    // Properties
   int Count { get; }
   bool IsReadOnly { get; }
}

एक List<T>उपकरण IList<T>, जो विस्तार करता हैICollection<T>

public interface IList<T> : ICollection<T>
{
    // Methods
    int IndexOf(T item);
    void Insert(int index, T item);
    void RemoveAt(int index);

    // Properties
    T this[int index] { get; set; }
}

हैशसेट ने शब्दार्थ निर्धारित किया है, जिसे आंतरिक रूप से हैशटेबल के माध्यम से लागू किया गया है:

एक सेट एक संग्रह है जिसमें कोई डुप्लिकेट तत्व नहीं होते हैं, और जिनके तत्व किसी विशेष क्रम में नहीं होते हैं।

यदि यह सूचकांक / स्थिति / सूची व्यवहार को खो देता है, तो HashSet को क्या प्राप्त होता है?

HashSet से आइटम जोड़ना और पुनः प्राप्त करना हमेशा ऑब्जेक्ट द्वारा ही होता है, इंडेक्सर के माध्यम से नहीं, और O (1) ऑपरेशन के करीब होता है (सूची O (1) जोड़ें, O (1) इंडेक्स द्वारा प्राप्त होता है, O (n)) /हटाना)।

एक हाशसैट के व्यवहार की तुलना Dictionary<TKey,TValue>मूल्यों के रूप में केवल चाबियाँ जोड़ने / हटाने और स्वयं शब्दकोश मूल्यों की अनदेखी करके की जा सकती है । आपको शब्दकोश में कुंजियों की अपेक्षा होगी कि डुप्लिकेट मान न हों, और यह "सेट" भाग का बिंदु है।


14

प्रदर्शन हैशसेट को सूची में चुनने का एक बुरा कारण होगा। इसके बजाय, आपका इरादा क्या बेहतर है? यदि आदेश महत्वपूर्ण है, तो सेट करें (या हैशसेट) बाहर है। यदि डुप्लिकेट की अनुमति है, तो इसी तरह। लेकिन जब हम ऑर्डर की परवाह नहीं करते हैं, तो बहुत सारी परिस्थितियां होती हैं, और हमारे पास डुप्लिकेट नहीं होते - और जब आप सेट चाहते हैं।


21
Performance would be a bad reason to choose HashSet over List: मैं आपसे सहमत नहीं हूँ। यह कहने की तरह है कि दो सूचियों के बजाय एक Dictionray चुनने से प्रदर्शन में मदद नहीं मिलती है। निम्नलिखित लेख
ऑस्कर मेडेरोस

11
@ ऑस्कर: मैंने यह नहीं कहा कि सेट अधिक तेज़ नहीं हैं - मैंने कहा कि उन्हें चुनने का एक बुरा आधार होगा। यदि आप एक ऑर्डर किए गए संग्रह का प्रतिनिधित्व करने की कोशिश कर रहे हैं, तो एक सेट बस काम नहीं करेगा और इसे अंदर करने की कोशिश करना एक गलती होगी; यदि आप जो संग्रह चाहते हैं उसका कोई क्रम नहीं है, एक सेट एकदम सही है - और तेज़। लेकिन पहला सवाल क्या महत्वपूर्ण है: आप क्या प्रतिनिधित्व करने की कोशिश कर रहे हैं?
कार्ल मैन्स्टर

2
लेकिन इसके बारे में सोचो। यदि आप जाँचते रहना चाहते हैं कि क्या दिए गए तार 10,000 तार के कुछ संग्रह के सदस्य हैं, तकनीकी रूप से, string[].Containsऔर HashSet<string>.Containsअपने इरादे को समान रूप से व्यक्त करते हैं; हैशसेट लेने का कारण यह बहुत तेज चलेगा।
केसी

12

हैशसेट हैशिंग द्वारा लागू किया गया एक सेट है । एक सेट बिना डुप्लिकेट तत्वों वाले मूल्यों का एक संग्रह है। एक सेट में मान भी आमतौर पर unordered हैं। तो नहीं, एक सेट का उपयोग किसी सूची को बदलने के लिए नहीं किया जा सकता है (जब तक कि आपको पहली बार सेट का उपयोग नहीं करना चाहिए)।

यदि आप सोच रहे हैं कि एक सेट क्या अच्छा हो सकता है: कहीं भी आप डुप्लिकेट से छुटकारा पाना चाहते हैं, जाहिर है। एक छोटे से वंचित उदाहरण के रूप में, मान लीजिए कि आपके पास एक सॉफ़्टवेयर प्रोजेक्ट के 10.000 संशोधनों की सूची है, और आप यह जानना चाहते हैं कि कितने लोगों ने उस प्रोजेक्ट में योगदान दिया। आप Set<string>संशोधन की सूची पर एक और पुनरावृति का उपयोग कर सकते हैं और सेट में प्रत्येक संशोधन के लेखक को जोड़ सकते हैं। एक बार जब आप पुनरावृत्ति कर लेते हैं, तो सेट का आकार वह उत्तर होता है जिसे आप खोज रहे थे।


लेकिन सेट एकल तत्वों की पुनर्प्राप्ति की अनुमति नहीं देता है? सेट की तरह [45]?
जोहान वेन्ग

2
उसके लिए, आप सदस्यों को सेट पर पुन: व्यवस्थित करेंगे। अन्य विशिष्ट ऑपरेशन यह जाँच रहे हैं कि सेट में कोई तत्व है या सेट का आकार प्राप्त कर रहा है।
इल

11

एक IEnumerable संग्रह में डुप्लिकेट तत्वों को हटाने के लिए HashSet का उपयोग किया जाएगा। उदाहरण के लिए,

List<string> duplicatedEnumrableStrings = new List<string> {"abc", "ghjr", "abc", "abc", "yre", "obm", "ghir", "qwrt", "abc", "vyeu"};
HashSet<string> uniqueStrings = new HashSet(duplicatedEnumrableStrings);

उन कोडों को चलाने के बाद, यूनीकस्ट्रीम ने {"abc", "ghjr", "yre", "obm", "qwrt", "vyeu"};


6

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

और नहीं, आप एक सेट को अनुक्रमित नहीं कर सकते हैं, जो वैसे भी समझ में नहीं आएगा, क्योंकि सेट का आदेश नहीं दिया जाता है। यदि आप कुछ आइटम जोड़ते हैं, तो सेट याद नहीं होगा कि कौन सा पहले था, और कौन सा दूसरा आदि।


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

5

HashSet<T>.NET फ्रेमवर्क में एक डेटा स्ट्रक्टुट है जो एक गणितीय सेट को ऑब्जेक्ट के रूप में दर्शाने में सक्षम है । इस मामले में, यह GetHashCodeसेट तत्वों की समानता की तुलना करने के लिए हैश कोड ( प्रत्येक आइटम का परिणाम) का उपयोग करता है ।

एक सेट इस सूची में भिन्न होता है कि यह केवल उसी तत्व की एक घटना की अनुमति देता है जो इसके भीतर निहित है। यदि आप एक दूसरे समान तत्व को जोड़ने का प्रयास करते HashSet<T>हैं falseतो बस वापस आ जाएंगे । वास्तव में, तत्वों की खोज बहुत जल्दी ( O(1)समय) है, क्योंकि आंतरिक डेटा संरचना बस एक हैशटेबल है।

आप जो उपयोग करने के लिए सोच रहे हैं, ध्यान दें कि एक का उपयोग कर List<T>जहां HashSet<T>उपयुक्त है नहीं सबसे बड़ी गलती है, हालांकि यह संभावित है जहाँ आप अपने संग्रह में अवांछनीय डुप्लिकेट आइटम नहीं हैं समस्याओं की अनुमति दे सकता है। क्या अधिक है, लुकअप (आइटम पुनर्प्राप्ति) बहुत अधिक कुशल है - आदर्श O(1)(आदर्श बकेटिंग के लिए) O(n)समय के बजाय - जो कई परिदृश्यों में काफी महत्वपूर्ण है।


1
किसी सेट में मौजूदा आइटम जोड़ने से अपवाद नहीं होगा। जोड़ बस झूठे लौटेंगे। इसके अलावा: तकनीकी रूप से हैश लुकिंग O (n) है, O (1) नहीं, जब तक कि आपके पास एक सही हैशिंग फ़ंक्शन न हो। जब तक हैशिंग फ़ंक्शन वास्तव में खराब नहीं होता, तब तक आप निश्चित रूप से इसे हे (1) मानकर दूर हो जाएंगे।
sepp2k

1
@ sepp2k: हाँ, तो यह एक बूलियन देता है ... मुद्दा यह है, यह आपको सूचित करता है। और हैश देखो सबसे खराब स्थिति है ओ (एन) यदि आप बाल्टी कर रहे हैं तो भयानक है - यह सामान्य रूप से ओ (1) के बहुत करीब है।
नोल्डोरिन

4

List<T>सूचना के सेट किए गए स्टोर को संग्रहीत करने के लिए उपयोग किया जाता है। यदि आप सूची के तत्वों के सापेक्ष क्रम को जानते हैं, तो आप उन्हें निरंतर समय में एक्सेस कर सकते हैं। हालाँकि, यह निर्धारित करने के लिए कि कोई तत्व सूची में कहाँ है या यह जाँचने के लिए कि क्या यह सूची में मौजूद है, लुकअप समय रैखिक है। दूसरी ओर, HashedSet<T>संग्रहीत डेटा के क्रम की कोई गारंटी नहीं देता है और इसके परिणामस्वरूप इसके तत्वों के लिए निरंतर पहुंच समय प्रदान करता है।

जैसा कि नाम से पता चलता है, HashedSet<T>एक डेटा संरचना है जो लागू करता है शब्दार्थ निर्धारित करता है । डेटा संरचना सेट ऑपरेशन (यानी यूनियन, अंतर, इंटरसेक्ट) को लागू करने के लिए अनुकूलित है, जिसे पारंपरिक सूची कार्यान्वयन के साथ कुशलता से नहीं किया जा सकता है।

इसलिए, यह चुनने के लिए कि कौन सा डेटा प्रकार वास्तव में उपयोग करना है, यह इस बात पर निर्भर करता है कि आपके आवेदन के साथ क्या करने का प्रयास कर रहे हैं। यदि आप इस बात की परवाह नहीं करते हैं कि आपके तत्वों को एक संग्रह में कैसे ऑर्डर किया गया है, और केवल अस्तित्व, उपयोग के लिए एनमरेट करना या जांचना चाहते हैं HashSet<T>। अन्यथा, List<T>किसी अन्य उपयुक्त डेटा संरचना का उपयोग करने पर विचार करें ।


2
एक और चेतावनी: सेट आम तौर पर एक तत्व की केवल एक घटना की अनुमति देता है।
स्टीव गाइडी

1

संक्षेप में - कभी भी आपको एक डिक्शनरी (या एक डिक्शनरी जहाँ S T की संपत्ति है) का उपयोग करने के लिए लुभाया जाता है, तो आपको एक HashSet पर विचार करना चाहिए (या HashSet + T पर IEquatable को लागू करना जो S पर समान होता है)


5
जब तक आप कुंजी के बारे में परवाह नहीं करते हैं, तब आपको शब्दकोश का उपयोग करना चाहिए।
हार्डवेयरगुडी

1

HashSet<T>जब आप LINQ प्रदान करता है की तुलना में दो संग्रह पर अधिक विशिष्ट सेट संचालन चाहते हैं तो मूल इच्छित परिदृश्य में उपयोग किया जाना चाहिए। LINQ तरीकों की तरह Distinct, Union, Intersectऔर Exceptज्यादातर स्थितियों में पर्याप्त हैं, लेकिन कभी कभी आप अधिक परिष्कृत आपरेशन की आवश्यकता हो सकती है, और HashSet<T>प्रदान करता है:

  • UnionWith
  • IntersectWith
  • ExceptWith
  • SymmetricExceptWith
  • Overlaps
  • IsSubsetOf
  • IsProperSubsetOf
  • IsSupersetOf
  • IsProperSubsetOf
  • SetEquals

LINQ और HashSet<T>"ओवरलैपिंग" विधियों के बीच एक और अंतर यह है कि LINQ हमेशा एक नया रिटर्न देता है IEnumerable<T>, और HashSet<T>विधियाँ स्रोत संग्रह को संशोधित करती हैं।

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