2013-07-09 6 views
6

एक समस्या जो मैं अक्सर चलाता हूं उसे वस्तुओं के संग्रह को इस तरह से स्टोर करने की आवश्यकता होती है कि मैं उन्हें किसी विशेष फ़ील्ड/प्रॉपर्टी द्वारा पुनर्प्राप्त कर सकूं जो उस ऑब्जेक्ट के लिए एक अद्वितीय "अनुक्रमणिका" है। उदाहरण के लिए, मेरे पास Person ऑब्जेक्ट है जिसके लिए name फ़ील्ड एक अद्वितीय पहचानकर्ता है, और मैं Person ऑब्जेक्ट्स Person के कुछ संग्रह से पुनर्प्राप्त करने में सक्षम होना चाहता हूं जिसका name="Sax Russell" है। जावा में मैं आमतौर पर Map का उपयोग करके इसे पूरा करता हूं जहां मैं वास्तव में Set चाहता हूं, और हमेशा ऑब्जेक्ट के "अनुक्रमणिका" फ़ील्ड का उपयोग मानचित्र में इसकी कुंजी के रूप में करता हूं, यानी peopleMap.add(myPerson.getName(), myPerson)। मैं Dictionary के साथ सी # में ही बात कर के बारे में सोच रहा था, इस तरह:सी # संग्रह संपत्ति द्वारा अनुक्रमित?

class Person { 
    public string Name {get; set;} 
    public int Age {get; set;} 
    //... 
} 

Dictionary<string, Person> PersonProducerMethod() { 
    Dictionary<string, Person> people = new Dictionary<string, Person>(); 
    //somehow produce Person instances... 
    people.add(myPerson.Name, myPerson); 
    //... 
    return people; 
} 

void PersonConsumerMethod(Dictionary<string, Person> people, List<string> names) { 
    foreach(var name : names) { 
     person = people[name]; 
     //process person somehow... 
    } 
} 

हालांकि, इस अनाड़ी लगता है, और Dictionary और उसके मूल्यों की चाबियाँ के बीच एक नहीं बल्कि ढीला संयोजन से परिचित करवाता है मैं प्रत्येक Person स्टोर करने के लिए कुंजी के रूप में Name संपत्ति का उपयोग कर Person शब्दकोशों के प्रत्येक निर्माता पर निहित रूप से निर्भर करता हूं। मुझे कोई गारंटी नहीं है कि people["Sax Russell"] पर तत्व वास्तव में Name="Sax Russell" के साथ है जब तक कि मैं प्रत्येक बार शब्दकोश तक पहुंचने के लिए दो बार जांच नहीं करता।

स्पष्ट रूप से यह सुनिश्चित करने के लिए कुछ तरीका हो सकता है कि Person वस्तुओं का संग्रह कस्टम समानता तुलनाकर्ताओं और/या LINQ प्रश्नों का उपयोग करके नाम से अनुक्रमित किया गया हो? यह महत्वपूर्ण है कि लुकअप निरंतर रहें, यही कारण है कि मैं सिर्फ List.Find या Enumerable.Where का उपयोग नहीं कर सकता। मैंने HashSet का उपयोग करने और इसे समानता तुलनाकर्ता के साथ बनाने का प्रयास किया है जो कि दिए गए ऑब्जेक्ट्स के Name फ़ील्ड की तुलना करता है, लेकिन Person ऑब्जेक्ट्स को केवल उनके नाम का उपयोग करके पुनर्प्राप्त करने का कोई तरीका नहीं प्रतीत होता है।

+1

बस इस पर ठोकर खाई, लेकिन आप [KeyedCollection] (https पर विचार किया है

यहाँ इस तरह के एक संग्रह की एक कंकाल समाधान है: //msdn.microsoft.com/en-us/library/ms132438(v=vs.110).aspx) कक्षा? – ygoe

उत्तर

3

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

public class PropertyMap<K,V> : ICollection<V> { 
    private readonly IDictionary<K,V> dict = new Dictionary<K,V>(); 
    private readonly Func<V,K> key; 
    public PropertyMap(Func<V,K> key) { 
     this.key = key; 
    } 
    public void Add(V v) { 
     dict.Add(key(v)); 
    } 
    // Implement other methods of ICollection 
    public this[K k] { 
     get { return dict[k]; } 
     set { dict[k] = value; } 
    } 
} 

इसका इस्तेमाल करने के लिए है:

PropertyMap<string,Person> mp = new PropertyMap<string,Person>(
    p => p.Name 
); 
mp.Add(p1); 
mp.Add(p2); 
+0

मुझे यह पसंद है। निश्चित रूप से समस्या का एक अच्छा सामान्य समाधान। –

+0

दोनों उत्तर अच्छे हैं, लेकिन मुझे यह पसंद है कि यह कितना सामान्य है, और यह "इस ऑब्जेक्ट से एक कुंजी प्राप्त करने" की परिभाषा को समाहित करने के लिए सी # के फ़ंक्शन प्रतिनिधियों का लाभ कैसे लेता है। – Edward

+0

अब आपको एक लिंक प्रदाता है ताकि ऑब्जेक्ट्स के लिए लिंक लुकअप के लिए इंडेक्स का उपयोग करेगा: 'mp.Where (person => person.Name == "बॉब")।FirstOrDefault() ' –

6

मुझे यकीन नहीं है कि इसमें कुछ भी बनाया गया है जो आप चाहते हैं, लेकिन आप कुंजी को निर्दिष्ट करने वाले शब्दकोश को लपेटने से रोक नहीं सकते हैं, और IList<Person> लागू कर रहे हैं। यहां कुंजी (कोई इरादा नहीं है) उपभोक्ता को अंतर्निहित शब्दकोश तक पहुंच नहीं है, इसलिए आपको आश्वासन दिया जा सकता है कि चाबियाँ सटीक हैं। कार्यान्वयन की

भाग ऐसा दिखाई दे सकता, कस्टम इंडेक्सर ध्यान दें के रूप में अच्छी तरह से:

public partial class PersonCollection : IList<Person> 
{ 

    //the underlying dictionary 
    private Dictionary<string, Person> _dictionary; 

    public PersonCollection() 
    { 
     _dictionary = new Dictionary<string, Person>(); 
    } 

    public void Add(Person p) 
    { 
     _dictionary.Add(p.Name, p); 
    } 

    public Person this[string name] 
    { 
     get 
     { 
      return _dictionary[name]; 
     } 
    } 

} 

एक पक्ष बोनस के रूप में, आप भी बाद में लेने वाली कोड बदलने के लिए बिना कार्यान्वयन को बदलने के लिए स्वतंत्र हैं।

+0

यह वही है जो मैं कहने जा रहा था। :) –

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