समग्र कुंजी शब्दकोश


90

मेरे पास सूची में कुछ ऑब्जेक्ट हैं, List<MyClass>मान लीजिए कि MyClass के पास कई गुण हैं। मैं MyClass के 3 गुणों के आधार पर सूची का एक सूचकांक बनाना चाहूंगा। इस स्थिति में गुणों में से 2 अंतर हैं, और एक गुण एक डेटाइम है।

मूल रूप से मैं ऐसा कुछ करने में सक्षम होना चाहता हूं:

Dictionary< CompositeKey , MyClass > MyClassListIndex = Dictionary< CompositeKey , MyClass >();
//Populate dictionary with items from the List<MyClass> MyClassList
MyClass aMyClass = Dicitonary[(keyTripletHere)];

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


2
आप टुपल्स का उपयोग क्यों नहीं करते? वे आपके लिए सभी कंपोजिंग करते हैं।
एल्ड्रिच कॉंड्रम 12

21
मुझे नहीं पता कि मुझे कैसे जवाब देना है। आप उस प्रश्न को पूछते हैं जैसे कि आपने मान लिया है कि मैं जानबूझकर टुपल्स से बच रहा हूं।
एरोनल्स

6
क्षमा करें, मैंने इसे अधिक विस्तृत उत्तर के रूप में लिखा।
एल्ड्रिच कॉनंड्रम

1
एक कस्टम क्लास को लागू करने से पहले Tuple (Eldritch Conundrum द्वारा सुझाए गए) के बारे में पढ़ें - msdn.microsoft.com/en-us/library/system.tuple.aspx । वे बदलने में आसान हैं और आपको कस्टम कक्षाओं के निर्माण से बचाएंगे।
OSH

जवाबों:


105

आपको टुपल्स का उपयोग करना चाहिए। वे एक CompiteKey वर्ग के बराबर हैं, लेकिन आपके लिए समान () और GetHashCode () पहले से ही लागू हैं।

var myClassIndex = new Dictionary<Tuple<int, bool, string>, MyClass>();
//Populate dictionary with items from the List<MyClass> MyClassList
foreach (var myObj in myClassList)
    myClassIndex.Add(Tuple.Create(myObj.MyInt, myObj.MyBool, myObj.MyString), myObj);
MyClass myObj = myClassIndex[Tuple.Create(4, true, "t")];

या System.Linq का उपयोग कर

var myClassIndex = myClassList.ToDictionary(myObj => Tuple.Create(myObj.MyInt, myObj.MyBool, myObj.MyString));
MyClass myObj = myClassIndex[Tuple.Create(4, true, "t")];

जब तक आपको हैश की गणना को अनुकूलित करने की आवश्यकता नहीं है, तब तक ट्यूपल्स का उपयोग करना सरल है।

यदि बहुत सारी संपत्तियां हैं जिन्हें आप समग्र कुंजी में शामिल करना चाहते हैं, तो टुपल प्रकार का नाम बहुत लंबा हो सकता है, लेकिन आप टपल से अपना स्वयं का वर्ग व्युत्पन्न बनाकर नाम कम कर सकते हैं <...>।


** 2017 में संपादित किया गया **

C # 7 से शुरू होने वाला एक नया विकल्प है: वैल्यू टुपल्स । विचार समान है, लेकिन वाक्यविन्यास अलग है, हल्का:

प्रकार Tuple<int, bool, string>बन जाता है (int, bool, string), और मूल्य Tuple.Create(4, true, "t")बन जाता है (4, true, "t")

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


4
टपल कुंजी के लिए एक अच्छा उम्मीदवार नहीं है क्योंकि यह अधिक संख्या में हैश टक्कर बनाता है। stackoverflow.com/questions/12657348/…
paparazzo

1
@ ब्लम KeyValuePair<K,V>और अन्य संरचनाओं में एक डिफ़ॉल्ट हैश फ़ंक्शन होता है जिसे खराब माना जाता है ( अधिक विवरण के लिए देखें stackoverflow.com/questions/3841602/… )। Tuple<>हालाँकि, एक वैल्यू टाइप नहीं है, और इसका डिफ़ॉल्ट हैश फ़ंक्शन कम से कम सभी क्षेत्रों का उपयोग करेगा। कहा जा रहा है, यदि आपके कोड की मुख्य समस्या टकराव है, तो एक अनुकूलित लागू करें जो GetHashCode()आपके डेटा के अनुरूप हो।
एल्ड्रिच कोन्ड्रम

1
भले ही ट्यूपल मेरे परीक्षण से एक वैल्यू टाइप नहीं है, लेकिन यह बहुत अधिक टक्करों से ग्रस्त है
paparazzo

5
मुझे लगता है कि यह उत्तर अब पुराना है कि हमारे पास ValueTuples है। C # में उनके पास अच्छे सिंटैक्स हैं, और वे Tuples के रूप में दुगनी तेजी से GetHashCode करने लगते हैं - gist.github.com/ljw1004/61bc96700d0b03c17cbbdb51437a69
Lucian Wischik

3
@LucianWischik धन्यवाद, मैंने उनका उल्लेख करने के लिए उत्तर अपडेट किया है।
एल्ड्रिच कोन्ड्रम

22

सबसे अच्छा तरीका है कि मैं एक समग्र संरचना बनाने के लिए और संग्रह के साथ काम करते समय गति और सटीकता सुनिश्चित करने के लिए GetHashCode () और बराबर () तरीकों को ओवरराइड करने के लिए सुनिश्चित करें:

class Program
{
    static void Main(string[] args)
    {
        DateTime firstTimestamp = DateTime.Now;
        DateTime secondTimestamp = firstTimestamp.AddDays(1);

        /* begin composite key dictionary populate */
        Dictionary<CompositeKey, string> compositeKeyDictionary = new Dictionary<CompositeKey, string>();

        CompositeKey compositeKey1 = new CompositeKey();
        compositeKey1.Int1 = 11;
        compositeKey1.Int2 = 304;
        compositeKey1.DateTime = firstTimestamp;

        compositeKeyDictionary[compositeKey1] = "FirstObject";

        CompositeKey compositeKey2 = new CompositeKey();
        compositeKey2.Int1 = 12;
        compositeKey2.Int2 = 9852;
        compositeKey2.DateTime = secondTimestamp;

        compositeKeyDictionary[compositeKey2] = "SecondObject";
        /* end composite key dictionary populate */

        /* begin composite key dictionary lookup */
        CompositeKey compositeKeyLookup1 = new CompositeKey();
        compositeKeyLookup1.Int1 = 11;
        compositeKeyLookup1.Int2 = 304;
        compositeKeyLookup1.DateTime = firstTimestamp;

        Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup1]);

        CompositeKey compositeKeyLookup2 = new CompositeKey();
        compositeKeyLookup2.Int1 = 12;
        compositeKeyLookup2.Int2 = 9852;
        compositeKeyLookup2.DateTime = secondTimestamp;

        Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup2]);
        /* end composite key dictionary lookup */
    }

    struct CompositeKey
    {
        public int Int1 { get; set; }
        public int Int2 { get; set; }
        public DateTime DateTime { get; set; }

        public override int GetHashCode()
        {
            return Int1.GetHashCode() ^ Int2.GetHashCode() ^ DateTime.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj is CompositeKey)
            {
                CompositeKey compositeKey = (CompositeKey)obj;

                return ((this.Int1 == compositeKey.Int1) &&
                        (this.Int2 == compositeKey.Int2) &&
                        (this.DateTime == compositeKey.DateTime));
            }

            return false;
        }
    }
}

GetHashCode () पर एक MSDN आलेख:

http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx


मुझे नहीं लगता है कि वास्तव में 100% एक अद्वितीय हैशकोड होना निश्चित है, बस बहुत संभावना है।
हंस ओल्सन

यह बहुत अच्छी तरह से सच हो सकता है! लिंक्ड MSDN लेख के अनुसार, GetHashCode () को ओवरराइड करने का अनुशंसित तरीका है। हालाँकि, मैं अपने दिन-प्रतिदिन के काम में बहुत सी मिश्रित कुंजियों का उपयोग नहीं करता, मैं कुछ के लिए नहीं कह सकता।
एलन ई। शार्फेनबर्ग

4
हाँ। यदि आप डिक्शनरी के साथ Dictionary.FindEntry () डिसाइड करते हैं, तो आप देखेंगे कि हैशकोड और पूर्ण समानता दोनों का परीक्षण किया गया है। हैशकोड का परीक्षण पहले किया जाता है और, यदि यह विफल हो जाता है, तो पूर्ण-समता की जांच के बिना शॉर्ट-सर्किट की स्थिति। यदि हैश गुजरता है, तो समानता का परीक्षण भी किया जाता है।
जेसन क्लेबन

1
और हां, बराबरी के लिए भी बराबरी करनी चाहिए। यहां तक ​​कि अगर आपने किसी भी उदाहरण के लिए GetHashCode () रिटर्न 0 बनाया है, तो शब्दकोश अभी भी काम करेगा, यह सिर्फ धीमा होगा।
जेसन क्लेबन

2
बिल्‍ड टपल प्रकार हैश संयोजन को 'आपके h1 ^ h2' के बजाय '(h1 << 5) + h1 ^ h2' के रूप में लागू करता है। मुझे लगता है कि वे करते हैं कि टकराव से बचने के लिए दो वस्तुओं को हैश करने के लिए समान मूल्य के बराबर है।
एल्ड्रिच कॉनंड्रम

13

कैसे के बारे में Dictionary<int, Dictionary<int, Dictionary<DateTime, MyClass>>>?

यह आपको करने की अनुमति देगा:

MyClass item = MyData[8][23923][date];

1
यह एक बहुत अधिक वस्तु का निर्माण करेगा और फिर एक कंपोजिटकेय संरचना या वर्ग का उपयोग करेगा। और देखने के दो स्तर का उपयोग किया जाएगा के रूप में भी धीमी हो जाएगी।
इयान रिंगरोस

मेरा मानना ​​है कि यह तुलनाओं की एक ही संख्या है - मैं नहीं देखता कि कैसे कई और वस्तुएं होंगी - समग्र कुंजी अभी भी एक कुंजी की आवश्यकता है, और यह घटक मूल्यों या वस्तुओं और उन्हें धारण करने के लिए एक तानाशाह है। यह नेस्टेड तरीका है, आपको प्रत्येक ऑब्जेक्ट / मान के लिए आवरण कुंजी की आवश्यकता नहीं है, प्रत्येक अतिरिक्त घोंसले के स्तर के लिए एक अतिरिक्त तानाशाही है। तुम क्या सोचते हो?
जेसन क्लेबन

9
मेरे बेंचमार्किंग के आधार पर, जिसे मैंने 2 और 3 भागों के साथ कुंजी के साथ आज़माया था: एक नेस्टेड डिक्शनरी समाधान एक ट्यूपल कम्पोजिट कुंजी दृष्टिकोण का उपयोग करने की तुलना में 3-4x तेज है। हालांकि, टपल दृष्टिकोण बहुत आसान / टिडियर है।
रिकेल

5
@ रिकॉल मैं उन बेंचमार्क की पुष्टि कर सकता हूं, हम अपने कोड-बेस में एक प्रकार का उपयोग करते हैं, जिसे CompositeDictionary<TKey1, TKey2, TValue>(आदि) कहा जाता है, जो केवल विरासत में मिलता है Dictionary<TKey1, Dictionary<TKey2, TValue>>(या फिर बहुत से नेस्टेड शब्दकोशों की आवश्यकता होती है। पूरे प्रकार को जमीन से खुद को लागू करने के बिना। नेस्टेड शब्दकोश या कुंजियों को टाइप करने के लिए) यह सबसे तेज़ है जो हमें मिलता है।
एडम हल्ड्सवर्थ

1
नेस्टेड तानाशाही दृष्टिकोण केवल आधे (?) मामलों के लिए तेजी से होना चाहिए जहां डेटा मौजूद नहीं है, क्योंकि मध्यवर्ती शब्दकोशों पूर्ण हैश कोड गणना और तुलना को बायपास कर सकते हैं। डेटा की मौजूदगी में, इसे धीमा होना चाहिए क्योंकि बेसिक ऑपरेशंस जैसे Add, Contains आदि को तीन बार किया जाना चाहिए। मुझे यकीन है कि ट्यूलल एप्रोच के साथ मार्जिन ऊपर उल्लिखित बेंचमार्क में से कुछ में पीटा गया है। .NET ट्यूपल्स के कार्यान्वयन विस्तार के बारे में है जो कि बहुत खराब विचारशील है, जो बॉक्सिंग पेनल्टी यह मान प्रकार के लिए लाता है। एक ठीक से लागू ट्रिपल मैं स्मृति के साथ भी विचार कर रहा हूँ
nawfal

12

आप उन्हें एक संरचना में संग्रहीत कर सकते हैं और कुंजी के रूप में उपयोग कर सकते हैं:

struct CompositeKey
{
  public int value1;
  public int value2;
  public DateTime value3;
}

हैश कोड पाने के लिए लिंक: http://msdn.microsoft.com/en-us/library/system.valuetype.gethashcode.aspx


मैं .NET 3.5 पर अटका हुआ हूं, इसलिए मुझे Tupleएस तक पहुंच नहीं है इसलिए यह एक अच्छा समाधान है!
अनारोना

मुझे आश्चर्य है कि यह अधिक उत्थान नहीं है। यह एक सरल उपाय है जो टुप्ले से अधिक पठनीय है।
मार्क

1
Msdn के अनुसार यह ठीक है, अगर कोई फ़ील्ड संदर्भ प्रकार नहीं है, अन्यथा यह समानता के लिए प्रतिबिंब का उपयोग करता है।
ग्रेगर स्लेवेक

@ मार्क एक संरचना के साथ समस्या यह है कि इसका डिफ़ॉल्ट गेटहैशकोड () कार्यान्वयन वास्तव में संरचना के सभी क्षेत्रों (खराब शब्दकोश प्रदर्शन के लिए अग्रणी) का उपयोग करने की गारंटी नहीं देता है, जबकि ट्यूपल ऐसी गारंटी प्रदान करता है। मैंने इसका परीक्षण किया है। Gory details के लिए stackoverflow.com/questions/3841602/… देखें ।
एल्ड्रिच कोन्ड्रम

8

अब जब VS2017 / C # 7 सामने आ गया है, तो इसका सबसे अच्छा जवाब है ValueTuple का उपयोग करना:

// declare:
Dictionary<(string, string, int), MyClass> index;

// populate:
foreach (var m in myClassList) {
  index[(m.Name, m.Path, m.JobId)] = m;
}

// retrieve:
var aMyClass = index[("foo", "bar", 15)];

मैंने एक गुमनाम ValueTuple के साथ शब्दकोश घोषित करने के लिए चुना (string, string, int)। लेकिन मैं उन्हें नाम दे सकता था (string name, string path, int id)

परफ़ेक्टिव, नया वैल्यू टूपल, टपल की तुलना में तेज़ है, GetHashCodeलेकिन धीमा है Equals। मुझे लगता है कि आपको यह पता लगाने के लिए संपूर्ण एंड-टू-एंड प्रयोग करने की आवश्यकता है कि आपके परिदृश्य के लिए वास्तव में सबसे तेज़ क्या है। लेकिन ValueTuple के लिए एंड-टू-एंड निकनेस और लैंग्वेज सिंटैक्स इसे जीतता है।

// Perf from https://gist.github.com/ljw1004/61bc96700d0b03c17cf83dbb51437a69
//
//              Tuple ValueTuple KeyValuePair
//  Allocation:  160   100        110
//    Argument:   75    80         80    
//      Return:   75   210        210
//        Load:  160   170        320
// GetHashCode:  820   420       2700
//      Equals:  280   470       6800

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

5

दो वसंत तुरंत दिमाग में आते हैं:

  1. जैसा कि केविन ने सुझाव दिया था और एक संरचना लिखें जो आपकी कुंजी के रूप में काम करेगी। इस संरचना को लागू करने IEquatable<TKey>और इसके Equalsऔर GetHashCodeतरीकों को ओवरराइड करने के लिए सुनिश्चित करें *।

  2. आंतरिक रूप से नेस्टेड शब्दकोशों का उपयोग करने वाला एक वर्ग लिखें। कुछ की तरह: TripleKeyDictionary<TKey1, TKey2, TKey3, TValue>... इस वर्ग के आंतरिक प्रकार के एक सदस्य के लिए होता है Dictionary<TKey1, Dictionary<TKey2, Dictionary<TKey3, TValue>>>, और इस तरह के रूप में तरीकों का खुलासा होगा this[TKey1 k1, TKey2 k2, TKey3 k3], ContainsKeys(TKey1 k1, TKey2 k2, TKey3 k3)आदि

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

Equals मेथड का डिफाल्ट कार्यान्वयन obj और इसी उदाहरण के संबंधित क्षेत्रों की तुलना करने के लिए प्रतिबिंब का उपयोग करता है। विधि के प्रदर्शन में सुधार करने के लिए एक विशेष प्रकार के लिए बराबर पद्धति को ओवरराइड करें और अधिक बारीकी से प्रकार के लिए समानता की अवधारणा का प्रतिनिधित्व करें।


1 के बारे में, मुझे नहीं लगता कि यूओ को इक्वाल्स और गेटहैशकोड को ओवरराइड करने की आवश्यकता है, इक्वल्स का डिफ़ॉल्ट कार्यान्वयन स्वचालित रूप से सभी क्षेत्रों पर समानता के लिए जांच करेगा जो मुझे लगता है कि इस संरचना पर ठीक होना चाहिए।
हंस ओल्सन

@ जो: यह आवश्यक नहीं हो सकता है , लेकिन मैं किसी भी संरचना के लिए ऐसा करने की दृढ़ता से सलाह दूंगा जो एक कुंजी के रूप में काम करने जा रहा है। मेरा संपादन देखें।
दान ताओ

3

यदि कुंजी वर्ग का हिस्सा है तो उपयोग करें KeyedCollection
यह वह जगह है Dictionaryजहां कुंजी वस्तु से ली गई है।
कवर यह है शब्दकोश के तहत
Do में महत्वपूर्ण दोहराना नहीं है Keyऔर Value
क्यों एक मौका ले कुंजी के Keyरूप में ही नहीं है Value
स्मृति में एक ही जानकारी की नकल करने की जरूरत नहीं है।

कीडेक्लेक्शन क्लास

समग्र कुंजी को उजागर करने के लिए अनुक्रमणिका

    using System.Collections.ObjectModel;

    namespace IntIntKeyedCollection
    {
        class Program
        {
            static void Main(string[] args)
            {
                Int32Int32DateO iid1 = new Int32Int32DateO(0, 1, new DateTime(2007, 6, 1, 8, 30, 52));
                Int32Int32DateO iid2 = new Int32Int32DateO(0, 1, new DateTime(2007, 6, 1, 8, 30, 52));
                if (iid1 == iid2) Console.WriteLine("same");
                if (iid1.Equals(iid2)) Console.WriteLine("equals");
                // that are equal but not the same I don't override = so I have both features

                Int32Int32DateCollection int32Int32DateCollection = new Int32Int32DateCollection();
                // dont't have to repeat the key like Dictionary
                int32Int32DateCollection.Add(new Int32Int32DateO(0, 0, new DateTime(2008, 5, 1, 8, 30, 52)));
                int32Int32DateCollection.Add(new Int32Int32DateO(0, 1, new DateTime(2008, 6, 1, 8, 30, 52)));
                int32Int32DateCollection.Add(iid1);
                //this would thow a duplicate key error
                //int32Int32DateCollection.Add(iid2);
                //this would thow a duplicate key error
                //int32Int32DateCollection.Add(new Int32Int32DateO(0, 1, new DateTime(2008, 6, 1, 8, 30, 52)));
                Console.WriteLine("count");
                Console.WriteLine(int32Int32DateCollection.Count.ToString());
                // reference by ordinal postion (note the is not the long key)
                Console.WriteLine("oridinal");
                Console.WriteLine(int32Int32DateCollection[0].GetHashCode().ToString());
                // reference by index
                Console.WriteLine("index");
                Console.WriteLine(int32Int32DateCollection[0, 1, new DateTime(2008, 6, 1, 8, 30, 52)].GetHashCode().ToString());
                Console.WriteLine("foreach");
                foreach (Int32Int32DateO iio in int32Int32DateCollection)
                {
                    Console.WriteLine(string.Format("HashCode {0} Int1 {1} Int2 {2} DateTime {3}", iio.GetHashCode(), iio.Int1, iio.Int2, iio.Date1));
                }
                Console.WriteLine("sorted by date");
                foreach (Int32Int32DateO iio in int32Int32DateCollection.OrderBy(x => x.Date1).ThenBy(x => x.Int1).ThenBy(x => x.Int2))
                {
                    Console.WriteLine(string.Format("HashCode {0} Int1 {1} Int2 {2} DateTime {3}", iio.GetHashCode(), iio.Int1, iio.Int2, iio.Date1));
                }
                Console.ReadLine();
            }
            public class Int32Int32DateCollection : KeyedCollection<Int32Int32DateS, Int32Int32DateO>
            {
                // This parameterless constructor calls the base class constructor 
                // that specifies a dictionary threshold of 0, so that the internal 
                // dictionary is created as soon as an item is added to the  
                // collection. 
                // 
                public Int32Int32DateCollection() : base(null, 0) { }

                // This is the only method that absolutely must be overridden, 
                // because without it the KeyedCollection cannot extract the 
                // keys from the items.  
                // 
                protected override Int32Int32DateS GetKeyForItem(Int32Int32DateO item)
                {
                    // In this example, the key is the part number. 
                    return item.Int32Int32Date;
                }

                //  indexer 
                public Int32Int32DateO this[Int32 Int1, Int32 Int2, DateTime Date1]
                {
                    get { return this[new Int32Int32DateS(Int1, Int2, Date1)]; }
                }
            }

            public struct Int32Int32DateS
            {   // required as KeyCollection Key must be a single item
                // but you don't really need to interact with Int32Int32DateS directly
                public readonly Int32 Int1, Int2;
                public readonly DateTime Date1;
                public Int32Int32DateS(Int32 int1, Int32 int2, DateTime date1)
                { this.Int1 = int1; this.Int2 = int2; this.Date1 = date1; }
            }
            public class Int32Int32DateO : Object
            {
                // implement other properties
                public Int32Int32DateS Int32Int32Date { get; private set; }
                public Int32 Int1 { get { return Int32Int32Date.Int1; } }
                public Int32 Int2 { get { return Int32Int32Date.Int2; } }
                public DateTime Date1 { get { return Int32Int32Date.Date1; } }

                public override bool Equals(Object obj)
                {
                    //Check for null and compare run-time types.
                    if (obj == null || !(obj is Int32Int32DateO)) return false;
                    Int32Int32DateO item = (Int32Int32DateO)obj;
                    return (this.Int32Int32Date.Int1 == item.Int32Int32Date.Int1 &&
                            this.Int32Int32Date.Int2 == item.Int32Int32Date.Int2 &&
                            this.Int32Int32Date.Date1 == item.Int32Int32Date.Date1);
                }
                public override int GetHashCode()
                {
                    return (((Int64)Int32Int32Date.Int1 << 32) + Int32Int32Date.Int2).GetHashCode() ^ Int32Int32Date.GetHashCode();
                }
                public Int32Int32DateO(Int32 Int1, Int32 Int2, DateTime Date1)
                {
                    Int32Int32DateS int32Int32Date = new Int32Int32DateS(Int1, Int2, Date1);
                    this.Int32Int32Date = int32Int32Date;
                }
            }
        }
    }

मूल्य प्रकार fpr का उपयोग करने के लिए के रूप में प्रमुख Microsoft विशेष रूप से इसके खिलाफ सिफारिश करता है।

ValueType.GetHashCode

Tuple तकनीकी रूप से एक मूल्य प्रकार नहीं है, लेकिन समान लक्षण (हैश टकराव) से ग्रस्त है और एक कुंजी के लिए अच्छा उम्मीदवार नहीं है।


अधिक सही उत्तर के लिए +1। आश्चर्यचकित किसी ने पहले इसका उल्लेख नहीं किया। वास्तव में कैसे ओपी उद्देश्य संरचना का उपयोग करने, के आधार पर HashSet<T>एक उपयुक्त के साथ IEqualityComparer<T>एक विकल्प भी होगा। Btw, मुझे लगता है कि अगर आपका वर्ग नाम और अन्य सदस्य नाम बदल सकते हैं तो आपका जवाब वोटों को आकर्षित करेगा :)
nawfal

2

मैं एक विकल्प सुझा सकता हूं - एक अनाम वस्तु। यह वही है जिसका हम कई कुंजियों के साथ GroupBy LINQ पद्धति में उपयोग करते हैं।

var dictionary = new Dictionary<object, string> ();
dictionary[new { a = 1, b = 2 }] = "value";

यह अजीब लग सकता है, लेकिन मैंने Tuple.GetHashCode और new {a = 1, b = 2} बेंचमार्क किया है। GetHashCode विधियाँ और अनाम वस्तुएँ .NET 4.5.1 पर मेरी मशीन पर जीतती हैं:

ऑब्जेक्ट - 1000 चक्रों में 10000 कॉल के लिए 89,1732 एमएस

ट्यूपल - 1000 चक्रों में 10000 कॉल के लिए 738,4475 एमएस


omg, यह विकल्प मेरे दिमाग में कभी नहीं था ... मुझे नहीं पता कि अगर आप कंपोजिट कुंजी के रूप में एक जटिल प्रकार का उपयोग करते हैं तो यह अच्छा व्यवहार करेगा।
गेब्रियल एस्पिनोज़ा

यदि आप किसी ऑब्जेक्ट को (अनाम एक के बजाय) पास करते हैं, तो इस ऑब्जेक्ट के GetHashCode विधि के परिणाम का उपयोग किया जाएगा। यदि आप इसका उपयोग करते हैं dictionary[new { a = my_obj, b = 2 }]तो परिणामी हैश कोड my_obj.GetHashCode और ((Int32) 2) .GetHashCode का संयोजन होगा।
माइकल लोगुटोव

इस विधि का उपयोग न करें! विभिन्न विधानसभाएं गुमनाम प्रकारों के लिए अलग-अलग नाम बनाती हैं। हालांकि यह आपके लिए गुमनाम दिखता है, पर्दे के पीछे एक ठोस वर्ग बनाया गया है और दो अलग-अलग वर्गों की दो वस्तुएं डिफ़ॉल्ट ऑपरेटर के बराबर नहीं होंगी।
क्वार्कली

और इस मामले में यह कैसे मायने रखता है?
माइकल लोगुटोव

0

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

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