2012-04-10 160 views
18

我创建字典对象c#dictionary如何为单个键添加多个值?

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

这是一个遗憾,他们没有包含一个可变的'Lookup'实现。很多逻辑已经存在,你只是不能添加项目。 – 2012-04-10 13:46:33

回答

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); 

O r List<string>与你的情况一样。另外,如果您知道要添加到动态集合(例如List<T>)中的项目数量,请支持使用初始列表容量的构造函数:new List<int>(100);

这会抓取满足指定容量的内存预先,而不是在每次开始填满时抓取小块。如果你知道你有100个键,你可以用字典来做。

+0

这(总是)需要2个查找。 – 2012-04-10 13:47:35

+2

使用TryGetValue会比ContainsKey更高效,并重新索引到字典中。 – roken 2012-04-10 13:48:00

+1

@Roken我知道,但这不是问题的关键。我从未见过以这种方式使用字典导致的任何有价值的性能问题。过早或微观优化充其量。 – 2012-04-10 13:49:39

6

如果我明白你想要什么:

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

后...

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

当您添加一个字符串,采取不同的方式取决于密钥是否已经或不存在。要添加字符串value为重点key

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

如果你打算把它带到这个抽象层次,为什么不使用'Dictionary >'。您只对内部集合执行add/remove/contains检查,这是HashSet的理想之处。 – Servy 2012-04-10 13:42:47

+1

语义略有不同。我的实现允许您为相同的密钥多次插入相同的值。我不知道这两个变体是否有不同的术语。 “MultiMap”适用于哪一个?对于我的变体可能是'MultiMap',您的变体可能是'MultiSet'? – 2012-04-10 13:50:12

+0

我根本不会使用继承。这个类的用户希望Dictionary接口完全隐藏。您可能需要一个MultiMap或一个字典,但不是两者都有。 – Trap 2013-10-01 10:38:38

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(在if内部)。否则,密钥存在,所以只需在该密钥下的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 2012-04-11 05:19:49

2

使用NameValuedCollection。

良好的起点是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 2012-04-11 05:21:23

+0

1.它是一个NameValueCollection - 没有'd'和2.注意你应该使用GetValues(String)而不是索引器 - 索引器返回一个逗号分隔的字符串与你的值,这是有问题的如果你的值可能包含一个逗号,并且3.集合不能区分null作为value或null作为key-not-found – toong 2013-07-02 10:10:37

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); 

它不会显示任何异常,不会替换以前的值。

相关问题