2009-06-05 5 views
88

में शब्दकोश कुंजी के रूप में टुपल्स (या सरणी) मैं सी # में एक शब्दकोश लुकअप टेबल बनाने की कोशिश कर रहा हूं। मुझे एक स्ट्रिंग में 3-टुपल मानों को हल करने की आवश्यकता है। मैंने सरणी के रूप में सरणी का उपयोग करने की कोशिश की, लेकिन यह काम नहीं किया, और मुझे नहीं पता कि और क्या करना है। इस बिंदु पर मैं शब्दकोशों के शब्दकोशों का शब्दकोश बनाने पर विचार कर रहा हूं, लेकिन शायद यह देखने के लिए बहुत सुंदर नहीं होगा, हालांकि मैं जावास्क्रिप्ट में ऐसा करता हूं।सी #

उत्तर

95

आप .NET 4.0 पर हैं, तो एक टपल का उपयोग करें:

lookup = new Dictionary<Tuple<TypeA, TypeB, TypeC>, string>(); 

आप एक टपल नहीं परिभाषित करने और उपयोग करने वाले कर सकते हैं कुंजी के रूप में। टपल GetHashCode ओवरराइड करने के लिए की जरूरत है, के बराबर है और IEquatable:

struct Tuple<T, U, W> : IEquatable<Tuple<T,U,W>> 
{ 
    readonly T first; 
    readonly U second; 
    readonly W third; 

    public Tuple(T first, U second, W third) 
    { 
     this.first = first; 
     this.second = second; 
     this.third = third; 
    } 

    public T First { get { return first; } } 
    public U Second { get { return second; } } 
    public W Third { get { return third; } } 

    public override int GetHashCode() 
    { 
     return first.GetHashCode()^second.GetHashCode()^third.GetHashCode(); 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null || GetType() != obj.GetType()) 
     { 
      return false; 
     } 
     return Equals((Tuple<T, U, W>)obj); 
    } 

    public bool Equals(Tuple<T, U, W> other) 
    { 
     return other.first.Equals(first) && other.second.Equals(second) && other.third.Equals(third); 
    } 
} 
+1

वीएस -2010 बीटा की एक प्रति डाउनलोड करें, और आप व्यक्तिगत रूप से पुष्टि कर सकते हैं कि वास्तविक तथ्य में ऐसा एक प्रकार .NET 4.0 पुस्तकालयों में है;) – jerryjvl

+5

इस संरचना को IEquatable > को भी कार्यान्वित करना चाहिए। इस तरह आप बॉक्सिंग से बच सकते हैं जब हैश कोड टकराव के मामले में बराबर() कहा जाता है। –

+0

धन्यवाद डस्टिन। इसे उदाहरण में जोड़ा गया। – Hallgrim

4

मैं आपके टुपल को उचित GetHashCode के साथ अधिभारित कर दूंगा, और इसे केवल कुंजी के रूप में उपयोग करूंगा।

जब तक आप उचित तरीकों को अधिभारित करते हैं, तो आपको सभ्य प्रदर्शन देखना चाहिए।

+1

IComparable कोई जरूरत नहीं में कुंजीपटल कैसे संग्रहीत या स्थित हैं, इस पर कोई प्रभाव नहीं पड़ता है। यह सब GetHashCode() और एक IEqualityComparer के माध्यम से किया जाता है। IEquatable कार्यान्वित करने से बेहतर प्रदर्शन प्राप्त होगा क्योंकि यह डिफ़ॉल्ट समानता कॉम्पैडर के कारण मुक्केबाजी को कम करता है, जो बराबर (ऑब्जेक्ट) फ़ंक्शन पर वापस आ जाता है। –

+0

मैं गेटहाशकोड का उल्लेख करने जा रहा था, लेकिन मैंने सोचा था कि इस मामले में डिक्शनरी आईकॉम्पेर्बल का उपयोग करती है, जिसमें हैशकोड समान थे ... अनुमान है कि मैं गलत था। –

6

तुम सच में अपने स्वयं के टपल वर्ग बनाने, या .NET 4.0 में निर्मित पर का उपयोग कर से बचना चाहते हैं किसी कारण से, वहाँ एक अन्य दृष्टिकोण संभव है; आप तीन प्रमुख मानों को एक ही मान में एक साथ जोड़ सकते हैं।

उदाहरण के लिए, यदि तीन मान पूर्णांक प्रकार हैं तो एक साथ 64 बिट्स नहीं लेते हैं, तो आप उन्हें ulong में जोड़ सकते हैं।

सबसे खराब स्थिति आप हमेशा एक स्ट्रिंग का उपयोग कर सकते हैं, जब तक आप सुनिश्चित करते हैं कि इसमें तीन घटक कुछ वर्ण या अनुक्रम से सीमित हैं जो कुंजी के घटकों के अंदर नहीं होते हैं, उदाहरण के लिए, तीन संख्याओं के साथ आज़मा सकते हैं:

string.Format("{0}#{1}#{2}", key1, key2, key3) 

स्पष्ट रूप से इस दृष्टिकोण में कुछ रचना भूमि के ऊपर नहीं है, लेकिन क्या आप इसे इस के लिए उपयोग कर रहे हैं पर निर्भर करता है काफी तुच्छ इसके बारे में देखभाल करने के लिए नहीं हो सकता।

+17

जबकि यह * काम करेगा, इसमें खराब कोड गंध है। –

+4

मैं कहूंगा कि यह संदर्भ पर दृढ़ता से निर्भर करता है; अगर मेरे पास गठबंधन करने के लिए तीन पूर्णांक प्रकार थे, और प्रदर्शन महत्वपूर्ण नहीं था, तो यह गलती करने के न्यूनतम मौके के साथ पूरी तरह से ठीक काम करता है। बेशक, यह सब .NET 4 के रूप में पूरी तरह से अनावश्यक है, क्योंकि माइक्रोसॉफ्ट हमें बॉक्स के बाहर ट्यूपल प्रकार (संभवतः सही!) प्रदान करेगा। – jerryjvl

+0

बड़े डोमेन के लिए अच्छा विचार। – ymihere

3

यहाँ संदर्भ के लिए नेट टपल है:

[Serializable] 
public class Tuple<T1, T2, T3> : IStructuralEquatable, IStructuralComparable, IComparable, ITuple { 

    private readonly T1 m_Item1; 
    private readonly T2 m_Item2; 
    private readonly T3 m_Item3; 

    public T1 Item1 { get { return m_Item1; } } 
    public T2 Item2 { get { return m_Item2; } } 
    public T3 Item3 { get { return m_Item3; } } 

    public Tuple(T1 item1, T2 item2, T3 item3) { 
     m_Item1 = item1; 
     m_Item2 = item2; 
     m_Item3 = item3; 
    } 

    public override Boolean Equals(Object obj) { 
     return ((IStructuralEquatable) this).Equals(obj, EqualityComparer<Object>.Default);; 
    } 

    Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) { 
     if (other == null) return false; 

     Tuple<T1, T2, T3> objTuple = other as Tuple<T1, T2, T3>; 

     if (objTuple == null) { 
      return false; 
     } 

     return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3); 
    } 

    Int32 IComparable.CompareTo(Object obj) { 
     return ((IStructuralComparable) this).CompareTo(obj, Comparer<Object>.Default); 
    } 

    Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) { 
     if (other == null) return 1; 

     Tuple<T1, T2, T3> objTuple = other as Tuple<T1, T2, T3>; 

     if (objTuple == null) { 
      throw new ArgumentException(Environment.GetResourceString("ArgumentException_TupleIncorrectType", this.GetType().ToString()), "other"); 
     } 

     int c = 0; 

     c = comparer.Compare(m_Item1, objTuple.m_Item1); 

     if (c != 0) return c; 

     c = comparer.Compare(m_Item2, objTuple.m_Item2); 

     if (c != 0) return c; 

     return comparer.Compare(m_Item3, objTuple.m_Item3); 
    } 

    public override int GetHashCode() { 
     return ((IStructuralEquatable) this).GetHashCode(EqualityComparer<Object>.Default); 
    } 

    Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { 
     return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3)); 
    } 

    Int32 ITuple.GetHashCode(IEqualityComparer comparer) { 
     return ((IStructuralEquatable) this).GetHashCode(comparer); 
    } 
    public override string ToString() { 
     StringBuilder sb = new StringBuilder(); 
     sb.Append("("); 
     return ((ITuple)this).ToString(sb); 
    } 

    string ITuple.ToString(StringBuilder sb) { 
     sb.Append(m_Item1); 
     sb.Append(", "); 
     sb.Append(m_Item2); 
     sb.Append(", "); 
     sb.Append(m_Item3); 
     sb.Append(")"); 
     return sb.ToString(); 
    } 

    int ITuple.Size { 
     get { 
      return 3; 
     } 
    } 
} 
+3

युक्त तार थे, तो यह वास्तविक गन्दा हो सकता है (हैश कोड प्राप्त करें) ((item1^item2) * 33)^कई सटीक अवलोकनों के लिए item3 –

2

अपने उपभोक्ता कोड शब्दकोश का एक IDictionary <> इंटरफेस के साथ करते हैं, बजाय कर सकते हैं, मेरी वृत्ति के साथ एक SortedDictionary <> उपयोग करने के लिए हो गया होता एक कस्टम सरणी comparer, अर्थात्:

class ArrayComparer<T> : IComparer<IList<T>> 
    where T : IComparable<T> 
{ 
    public int Compare(IList<T> x, IList<T> y) 
    { 
     int compare = 0; 
     for (int n = 0; n < x.Count && n < y.Count; ++n) 
     { 
      compare = x[n].CompareTo(y[n]); 
     } 
     return compare; 
    } 
} 

और बनाने के इस प्रकार (का उपयोग कर पूर्णांक [] सिर्फ ठोस उदाहरण के लिये):

var dictionary = new SortedDictionary<int[], string>(new ArrayComparer<int>()); 
30

टुपल और नेस्टेड शब्दकोश आधारित दृष्टिकोणों के बीच, टुपल आधारित के लिए जाना हमेशा बेहतर होता है।

दृश्य के रख-रखाव की दृष्टि से,

  • इसकी बहुत आसान है कि तरह लग रहा है एक कार्यक्षमता लागू करने के लिए:

    var myDict = new Dictionary<Tuple<TypeA, TypeB, TypeC>, string>(); 
    

    से
    var myDict = new Dictionary<TypeA, Dictionary<TypeB, Dictionary<TypeC, string>>>(); 
    
    कॉल प्राप्त करने वाला की ओर से

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

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

प्रदर्शन परिप्रेक्ष्य, सबसे अच्छा निष्कर्ष आप तक पहुँच सकते हैं से यह अपने आप को मापने के द्वारा है। लेकिन वहाँ कुछ सैद्धांतिक सीमाओं जो आप पहले से विचार कर सकते हैं कर रहे हैं:

  • नेस्ट शब्दकोश मामले में, हर कुंजी के लिए एक अतिरिक्त शब्दकोश (बाहरी और भीतरी) होने कुछ स्मृति भूमि के ऊपर होगा (की तुलना में अधिक है जो एक टपल बनाने होगा)।

  • नेस्टेड शब्दकोश मामले में, दो मूल शब्दकोशों जैसे जोड़, अद्यतन, लुकअप, हटाने आदि की आवश्यकता होती है। अब एक ऐसा मामला है जहां नेस्टेड डिक्शनरी दृष्टिकोण तेजी से हो सकता है, यानी, जब डेटा देखा जा रहा है, अनुपस्थित है, क्योंकि इंटरमीडिएट डिक्शनरी पूर्ण हैश कोड गणना & तुलना को बाईपास कर सकती है, लेकिन फिर इसे सुनिश्चित करने के लिए समय होना चाहिए। डेटा की उपस्थिति में, यह धीरे-धीरे होना चाहिए क्योंकि लुकअप दो बार किया जाना चाहिए (या घोंसले के आधार पर तीन बार)।

  • ट्यूपल दृष्टिकोण के संबंध में, .NET tuples सबसे अधिक प्रदर्शन नहीं करते हैं जब उनका सेट Equals and GetHashCode implementation causes boxing for value types के बाद सेट में कुंजी के रूप में उपयोग किया जाता है।

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

  1. अनुक्रमणिका शैली कॉल एक बहुत क्लीनर और सहज ज्ञान युक्त हो सकता है:


    एक तरफ ध्यान दें पर, कुछ सौंदर्य प्रसाधन शांत शब्दकोश कर सकते हैं। उदाहरण के लिए,

    string foo = dict[a, b, c]; //lookup 
    dict[a, b, c] = ""; //update/insertion 
    

    तो जो आंतरिक रूप से सम्मिलन और लुकअप संभालती अपने शब्दकोश कक्षा में आवश्यक indexers बेनकाब।

  2. इसके अलावा, एक उपयुक्त IEnumerable इंटरफ़ेस को लागू करने और एक Add(TypeA, TypeB, TypeC, string) विधि है जो आप संग्रह प्रारंभकर्ता वाक्य रचना देना होगा, जैसे प्रदान करते हैं:

    new MultiKeyDictionary<TypeA, TypeB, TypeC, string> 
    { 
        { a, b, c, null }, 
        ... 
    }; 
    
+1

+1। इस तरह के उत्तर के रूप में एक उत्तर कुछ वोटों के लायक है। – pbalaga

+0

नेस्टेड शब्दकोशों के मामले में, इंडेक्सर सिंटैक्स इस तरह अधिक नहीं होगा: 'स्ट्रिंग foo = dict [a] [b] [c] '? –

+0

@StevenRands हाँ यह होगा। – nawfal

5

, अच्छा साफ, तेज़, आसान और पठनीय तरीका है:

बस एक ट्यूपल से व्युत्पन्न एक साधारण कुंजी वर्ग बनाएं।

कुछ इसी तरह जोड़ने के इस तरह:

public sealed class myKey : Tuple<TypeA, TypeB, TypeC> 
{ 
    public myKey(TypeA dataA, TypeB dataB, TypeC dataC) : base (dataA, dataB, dataC) { } 

    public TypeA DataA { get { return Item1; } } 

    public TypeB DataB { get { return Item2; } } 

    public TypeC DataC { get { return Item3; } } 
} 

तो तुम शब्दकोश के साथ उपयोग कर सकते हैं:

var myDictinaryData = new Dictionary<myKey, string>() 
{ 
    {new myKey(1, 2, 3), "data123"}, 
    {new myKey(4, 5, 6), "data456"}, 
    {new myKey(7, 8, 9), "data789"} 
}; 
  • तुम भी में शामिल होने या के लिए एक प्रमुख के रूप में अनुबंध में उपयोग कर सकते हैं
  • linq
  • में समूह इस तरह से जा रहा है कि आपने कभी आइटम 1, आइटम 2, आइटम 3का ऑर्डर टाइप न करें...
  • आप
  • याद या जहां IStructuralEquatable, IStructuralComparable, IComparable ओवरराइड करने के लिए कुछ
  • कोई जरूरत प्राप्त करने के लिए जाने के लिए समझने के लिए कोड को जांच के लिए, ITuple वे सब यहाँ alredy
+0

मुझे लगता है कि यह सबसे सुंदर समाधान है –