2012-04-10 18 views
18

मैं वस्तुसी # शब्दकोश एकल कुंजी के लिए एकाधिक मान कैसे जोड़ें?

Dictionary<string, List<string>> dictionary = 
    new Dictionary<string,List<string>>(); 

मैं किसी दिए गए एकल कुंजी के लिए स्ट्रिंग की सूची में स्ट्रिंग मान जोड़ना चाहते हैं शब्दकोश बनाया है। यदि कुंजी पहले से मौजूद नहीं है तो मुझे एक नई कुंजी जोड़नी होगी। List<string> पूर्वनिर्धारित नहीं है, मेरा मतलब है कि मैंने कोई सूची वस्तु नहीं बनाई है और फिर dictionary.Add("key",Listname) पर आपूर्ति की है। dictionary.Add("key",Listname) में डायनामिक रूप से इस सूची ऑब्जेक्ट को कैसे बनाएं और फिर इस सूची में स्ट्रिंग जोड़ें। अगर मुझे 100 कुंजी जोड़नी है तो क्या मुझे dictionary.Add निर्देश निष्पादित करने से पहले 100 सूचियां बनाना होगा और क्या मुझे इन सूचियों की सामग्री को फिर से परिभाषित करना होगा?

धन्यवाद।

+0

यह एक शर्म की बात है कि उन्होंने एक परिवर्तनीय 'लुकअप' कार्यान्वयन शामिल नहीं किया है। बहुत सारे तर्क पहले से ही हैं, आप बस इसमें आइटम नहीं जोड़ सकते हैं। –

उत्तर

25

अद्यतन: TryGetValue का उपयोग कर अस्तित्व के लिए जांच मामले में केवल एक ही देखने करने के लिए तुम कहाँ सूची है:

List<int> list; 

if (!dictionary.TryGetValue("foo", out list)) 
{ 
    list = new List<int>(); 
    dictionary.Add("foo", list); 
} 

list.Add(2); 


मूल: अस्तित्व के लिए चेक और एक बार, तो कुंजी जोड़ने सूची प्राप्त करने के लिए शब्दकोश में और सामान्य में सूची में जोड़ें:

var dictionary = new Dictionary<string, List<int>>(); 

if (!dictionary.ContainsKey("foo")) 
    dictionary.Add("foo", new List<int>()); 

dictionary["foo"].Add(42); 
dictionary["foo"].AddRange(oneHundredInts); 

हे आपके मामले में आर List<string>

एक तरफ के रूप में, यदि आप जानते हैं कि आप List<T> जैसे गतिशील संग्रह में कितने आइटम जोड़ने जा रहे हैं, तो आरंभकर्ता सूची क्षमता लेने वाले निर्माता का समर्थन करें: new List<int>(100);

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

+0

यह (हमेशा) 2 लुकअप लेता है। –

+2

TryGetValue का उपयोग ContainsKey से अधिक प्रदर्शनकारी और शब्दकोश में reindexing होगा। – roken

+1

@ रोकेन मुझे पता है, लेकिन यह सवाल का क्रूक्स नहीं है। न ही मैंने कभी भी इस तरह के शब्दकोशों का उपयोग करने से व्युत्पन्न प्रदर्शन के मुद्दों को देखा है। सबसे अच्छा समय से पहले या माइक्रो अनुकूलन। –

6

तो मैं समझ गया कि आप क्या चाहते:

dictionary.Add("key", new List<string>()); 

बाद में ...

dictionary["key"].Add("string to your list"); 
0

जब आप एक स्ट्रिंग जोड़ने के लिए, इसे दूसरे तरीके से कुंजी पहले से है या नहीं मौजूद है जो इस पर निर्भर करते हैं। कुंजी key के लिए स्ट्रिंग value जोड़ने के लिए:

List<string> list; 
if (dictionary.ContainsKey(key)) { 
    list = dictionary[key]; 
} else { 
    list = new List<string>(); 
    dictionary.Add(ley, list); 
} 
list.Add(value); 
3

आप एक मल्टीमैप है, जो एक Dictionary<K, List<V>> से निकला है की मेरी कार्यान्वयन इस्तेमाल कर सकते हैं। यह सही नहीं है, हालांकि यह एक अच्छा काम करता है।

/// <summary> 
/// Represents a collection of keys and values. 
/// Multiple values can have the same key. 
/// </summary> 
/// <typeparam name="TKey">Type of the keys.</typeparam> 
/// <typeparam name="TValue">Type of the values.</typeparam> 
public class MultiMap<TKey, TValue> : Dictionary<TKey, List<TValue>> 
{ 

    public MultiMap() 
     : base() 
    { 
    } 

    public MultiMap(int capacity) 
     : base(capacity) 
    { 
    } 

    /// <summary> 
    /// Adds an element with the specified key and value into the MultiMap. 
    /// </summary> 
    /// <param name="key">The key of the element to add.</param> 
    /// <param name="value">The value of the element to add.</param> 
    public void Add(TKey key, TValue value) 
    { 
     List<TValue> valueList; 

     if (TryGetValue(key, out valueList)) { 
      valueList.Add(value); 
     } else { 
      valueList = new List<TValue>(); 
      valueList.Add(value); 
      Add(key, valueList); 
     } 
    } 

    /// <summary> 
    /// Removes first occurence of an element with a specified key and value. 
    /// </summary> 
    /// <param name="key">The key of the element to remove.</param> 
    /// <param name="value">The value of the element to remove.</param> 
    /// <returns>true if the an element is removed; 
    /// false if the key or the value were not found.</returns> 
    public bool Remove(TKey key, TValue value) 
    { 
     List<TValue> valueList; 

     if (TryGetValue(key, out valueList)) { 
      if (valueList.Remove(value)) { 
       if (valueList.Count == 0) { 
        Remove(key); 
       } 
       return true; 
      } 
     } 
     return false; 
    } 

    /// <summary> 
    /// Removes all occurences of elements with a specified key and value. 
    /// </summary> 
    /// <param name="key">The key of the elements to remove.</param> 
    /// <param name="value">The value of the elements to remove.</param> 
    /// <returns>Number of elements removed.</returns> 
    public int RemoveAll(TKey key, TValue value) 
    { 
     List<TValue> valueList; 
     int n = 0; 

     if (TryGetValue(key, out valueList)) { 
      while (valueList.Remove(value)) { 
       n++; 
      } 
      if (valueList.Count == 0) { 
       Remove(key); 
      } 
     } 
     return n; 
    } 

    /// <summary> 
    /// Gets the total number of values contained in the MultiMap. 
    /// </summary> 
    public int CountAll 
    { 
     get 
     { 
      int n = 0; 

      foreach (List<TValue> valueList in Values) { 
       n += valueList.Count; 
      } 
      return n; 
     } 
    } 

    /// <summary> 
    /// Determines whether the MultiMap contains an element with a specific 
    /// key/value pair. 
    /// </summary> 
    /// <param name="key">Key of the element to search for.</param> 
    /// <param name="value">Value of the element to search for.</param> 
    /// <returns>true if the element was found; otherwise false.</returns> 
    public bool Contains(TKey key, TValue value) 
    { 
     List<TValue> valueList; 

     if (TryGetValue(key, out valueList)) { 
      return valueList.Contains(value); 
     } 
     return false; 
    } 

    /// <summary> 
    /// Determines whether the MultiMap contains an element with a specific value. 
    /// </summary> 
    /// <param name="value">Value of the element to search for.</param> 
    /// <returns>true if the element was found; otherwise false.</returns> 
    public bool Contains(TValue value) 
    { 
     foreach (List<TValue> valueList in Values) { 
      if (valueList.Contains(value)) { 
       return true; 
      } 
     } 
     return false; 
    } 

} 

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

+0

यदि आप इसे अबास्ट्रक्शन के इस स्तर पर ले जा रहे हैं तो क्यों 'शब्दकोश > 'का उपयोग न करें।आप केवल आंतरिक संग्रह पर जोड़/निकालें/चेक भी करते हैं, जो हैशसेट आदर्श है। – Servy

+1

अर्थशास्त्र थोड़ा अलग है। मेरा कार्यान्वयन आपको एक ही कुंजी के लिए कई बार एक ही मान डालने की अनुमति देता है। मुझे नहीं पता कि इन दो प्रकारों के लिए अलग-अलग शर्तें हैं या नहीं। 'मल्टीमैप' किस पर लागू होता है? मेरे संस्करण के लिए 'मल्टीमैट' और आपके संस्करण के लिए 'मल्टीसेट' हो सकता है? –

+0

मैं विरासत का उपयोग नहीं करता था। इस वर्ग के उपयोगकर्ता चाहते हैं कि शब्दकोश इंटरफ़ेस पूरी तरह छिपा हुआ हो। आप या तो मल्टीमैप या एक शब्दकोश चाहते हैं, लेकिन दोनों नहीं। – Trap

5
Dictionary<string, List<string>> dictionary = new Dictionary<string,List<string>>(); 

foreach(string key in keys) { 
    if(!dictionary.ContainsKey(key)) { 
     //add 
     dictionary.Add(key, new List<string>()); 
    } 
    dictionary[key].Add("theString"); 
} 

यदि कुंजी मौजूद नहीं है, तो एक नया List जोड़ा गया है (अगर अंदर)। अन्यथा कुंजी मौजूद है, इसलिए उस कुंजी के नीचे List पर एक नया मान जोड़ें।

2

हालांकि लगभग अन्य प्रतिक्रियाओं के समान ही, मुझे लगता है कि यह इसे लागू करने का सबसे प्रभावी और संक्षिप्त तरीका है। TryGetValue का उपयोग ContainsKey का उपयोग करने से पहले और कुछ अन्य समाधानों के रूप में शब्दकोश में रीइंडेक्सिंग करने से तेज़ है।

void Add(string key, string val) 
{ 
    List<string> list; 

    if (!dictionary.TryGetValue(someKey, out list)) 
    { 
     values = new List<string>(); 
     dictionary.Add(key, list); 
    } 

    list.Add(val); 
} 
0

एक शब्दकोश का उपयोग करने के बजाय, क्यों एक ILookup में परिवर्तित नहीं?

var myData = new[]{new {a=1,b="frog"}, new {a=1,b="cat"}, new {a=2,b="giraffe"}}; 
ILookup<int,string> lookup = myData.ToLookup(x => x.a, x => x.b); 
IEnumerable<string> allOnes = lookup[1]; //enumerable of 2 items, frog and cat 

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

+0

धन्यवाद। मुझे अलग-अलग समय में आइटम जोड़ने की जरूरत है। – sailer

2

नाम ValuedCollection का उपयोग करें।

अच्छा प्रारंभ बिंदु here है। सीधे लिंक से।

System.Collections.Specialized.NameValueCollection myCollection 
    = new System.Collections.Specialized.NameValueCollection(); 

    myCollection.Add(“Arcane”, “http://arcanecode.com”); 
    myCollection.Add(“PWOP”, “http://dotnetrocks.com”); 
    myCollection.Add(“PWOP”, “http://dnrtv.com”); 
    myCollection.Add(“PWOP”, “http://www.hanselminutes.com”); 
    myCollection.Add(“TWIT”, “http://www.twit.tv”); 
    myCollection.Add(“TWIT”, “http://www.twit.tv/SN”); 
+0

धन्यवाद, यह भी अच्छा विकल्प – sailer

+0

1. यह एक नाम ValueCollection है - बिना 'डी' और 2. नोट करें कि आपको इंडेक्सर के बजाय GetValues ​​(स्ट्रिंग) का उपयोग करना चाहिए - इंडेक्सर आपके मानों के साथ अल्पविराम से अलग स्ट्रिंग देता है, जो समस्याग्रस्त है यदि आपके मूल्यों में कॉमा और 3. हो सकता है तो संग्रह शून्य के बीच शून्य या शून्य के रूप में अंतर नहीं करता है – toong

0

यहाँ एक ही जवाब के कई रूपों हैं :) मेरे एक और एक है और यह सहज तरीके के रूप में विस्तार प्रणाली का उपयोग करता है निष्पादित करने के लिए (काम):

public static void AddToList<T, U>(this IDictionary<T, List<U>> dict, T key, U elementToList) 
{ 

    List<U> list; 

    bool exists = dict.TryGetValue(key, out list); 

    if (exists) 
    { 
     dict[key].Add(elementToList); 
    } 
    else 
    { 
     dict[key] = new List<U>(); 
     dict[key].Add(elementToList); 
    } 

} 

तो आप इसका इस्तेमाल इस प्रकार है:

Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>(); 

dict.AddToList(4, "test1"); 
dict.AddToList(4, "test2"); 
dict.AddToList(4, "test3"); 

dict.AddToList(5, "test4"); 
0

एक NuGet पैकेज Microsoft Experimental Collections कि एक वर्ग MultiValueDictionary जो करता है आप वास्तव में क्या जरूरत है शामिल नहीं है।

Here पैकेज के निर्माता का ब्लॉग पोस्ट है जो इसे आगे बताता है।

Here एक और ब्लॉग पोस्ट है यदि आप उत्सुक महसूस कर रहे हैं।

उदाहरण उपयोग:

MultiDictionary<string, int> myDictionary = new MultiDictionary<string, int>(); 
myDictionary.Add("key", 1); 
myDictionary.Add("key", 2); 
myDictionary.Add("key", 3); 
//myDictionary["key"] now contains the values 1, 2, and 3 
0

मैं मौजूदा शब्दकोश में कुंजी करने के लिए सूची में जोड़ने के लिए कोशिश कर रहा था और निम्नलिखित समाधान तक पहुँच:

Dictionary<string,List<string>> NewParent = new Dictionary<string,List<string>>(); 
child = new List<string>(); 
child.Add('SomeData'); 
NewParent["item1"].AddRange(child); 

यह किसी भी अपवाद नहीं दिखाया जाएगा और नहीं होगा पिछले मानों को प्रतिस्थापित करें।

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