.NET字典中的重复键?
.NET基类库中是否有允许使用重复键的字典类? 我find的唯一解决scheme是创build一个类,例如:
Dictionary<string, List<object>>
但是这实际上使用起来很刺激。 在Java中,我相信一个MultiMap可以完成这个任务,但在.NET中找不到一个模拟器。
如果您使用的是.NET 3.5,请使用Lookup
类。
编辑:您通常使用Enumerable.ToLookup
创build一个Lookup
。 这确实假设你以后不需要改变它 – 但是我通常发现这已经足够好了。
如果这不适合你,我不认为有什么在框架中会有所帮助 – 并使用字典是一样好,因为:(
List类实际上对于包含重复项的键/值集合非常适用,您希望遍历集合。 例:
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>(); // add some values to the collection here for (int i = 0; i < list.Count; i++) { Print(list[i].Key, list[i].Value); }
这是List <KeyValuePair <string,string>>的一种方法
public class ListWithDuplicates : List<KeyValuePair<string, string>> { public void Add(string key, string value) { var element = new KeyValuePair<string, string>(key, value); this.Add(element); } } var list = new ListWithDuplicates(); list.Add("k1", "v1"); list.Add("k1", "v2"); list.Add("k1", "v3"); foreach(var item in list) { string x = string.format("{0}={1}, ", item.Key, item.Value); }
输出k1 = v1,k1 = v2,k1 = v3
如果使用string作为键和值,则可以使用System.Collections.Specialized.NameValueCollection ,它将通过GetValues(string key)方法返回一个string值数组。
我刚刚遇到PowerCollections库,其中包括一个名为MultiDictionary的类。 这整齐地包装这种types的function。
关于使用Lookup的非常重要的注意事项:
您可以通过对实现IEnumerable(T)
的对象调用ToLookup
来创buildLookup(TKey, TElement)
的实例。
没有公共构造函数来创build一个Lookup(TKey, TElement)
的新实例Lookup(TKey, TElement)
。 此外, Lookup(TKey, TElement)
对象是不可变的,也就是说,在创build后,您不能在Lookup(TKey, TElement)
对象中添加或移除元素或键。
(来自MSDN)
我认为这将成为大多数用途的展示瓶颈。
我认为像List<KeyValuePair<object, object>>
会做的工作。
如果您使用> = .NET 4,则可以使用Tuple
Class:
// declaration var list = new List<Tuple<string, List<object>>>(); // to add an item to the list var item = Tuple<string, List<object>>("key", new List<object>); list.Add(item); // to iterate foreach(var i in list) { Console.WriteLine(i.Item1.ToString()); }
看看C5的 HashBag类。
回答原来的问题。 像Dictionary<string, List<object>>
是在Code Project
MultiMap
类中实现的。
你可以find更多的信息到下面的链接: http : //www.codeproject.com/KB/cs/MultiKeyDictionary.aspx
NameValueCollection在一个键(也是一个string)下支持多个string值,但这是我知道的唯一例子。
当我遇到需要这种function的情况时,我倾向于创build类似于您示例中的构造的构造。
当使用List<KeyValuePair<string, object>>
选项时,可以使用LINQ来进行search:
List<KeyValuePair<string, object>> myList = new List<KeyValuePair<string, object>>(); //fill it here var q = from a in myList Where a.Key.Equals("somevalue") Select a.Value if(q.Count() > 0){ //you've got your value }
“滚动自己的”版本的允许“重复密钥”条目的字典很容易。 这是一个粗略简单的实现。 您可能要考虑添加基本上大部分(如果不是全部)对IDictionary<T>
。
public class MultiMap<TKey,TValue> { private readonly Dictionary<TKey,IList<TValue>> storage; public MultiMap() { storage = new Dictionary<TKey,IList<TValue>>(); } public void Add(TKey key, TValue value) { if (!storage.ContainsKey(key)) storage.Add(key, new List<TValue>()); storage[key].Add(value); } public IEnumerable<TKey> Keys { get { return storage.Keys; } } public bool ContainsKey(TKey key) { return storage.ContainsKey(key); } public IList<TValue> this[TKey key] { get { if (!storage.ContainsKey(key)) throw new KeyNotFoundException( string.Format( "The given key {0} was not found in the collection.", key)); return storage[key]; } } }
一个关于如何使用它的简单例子:
const string key = "supported_encodings"; var map = new MultiMap<string,Encoding>(); map.Add(key, Encoding.ASCII); map.Add(key, Encoding.UTF8); map.Add(key, Encoding.Unicode); foreach (var existingKey in map.Keys) { var values = map[existingKey]; Console.WriteLine(string.Join(",", values)); }
你的意思是一致的,而不是一个实际的重复? 否则散列表将无法工作。
一致意味着两个单独的密钥可以散列到等价值,但密钥不相等。
例如:说你的散列表的散列函数只是hashval =键模3,1和4都映射到1,但是是不同的值。 这就是你列表的想法发挥的地方。
当您需要查找1时,将该值散列为1,遍历该列表,直到findKey = 1。
如果允许插入重复键,则无法区分哪些键映射到哪些值。
我偶然发现了这个post寻找相同的答案,并没有发现,所以我用一个字典列表搭build了一个简单的示例解决scheme,覆盖[]运算符添加一个新的字典,当其他人有一个给定键(set),并返回一个值列表(get)。
这是丑陋和低效率,它只能获取/设置的关键,它总是返回一个列表,但它的工作原理:
class DKD { List<Dictionary<string, string>> dictionaries; public DKD(){ dictionaries = new List<Dictionary<string, string>>();} public object this[string key]{ get{ string temp; List<string> valueList = new List<string>(); for (int i = 0; i < dictionaries.Count; i++){ dictionaries[i].TryGetValue(key, out temp); if (temp == key){ valueList.Add(temp);}} return valueList;} set{ for (int i = 0; i < dictionaries.Count; i++){ if (dictionaries[i].ContainsKey(key)){ continue;} else{ dictionaries[i].Add(key,(string) value); return;}} dictionaries.Add(new Dictionary<string, string>()); dictionaries.Last()[key] =(string)value; } } }
我使用的方式只是一个
Dictionary<string, List<string>>
这样你就有一个键保存一个string列表。
例:
List<string> value = new List<string>(); if (dictionary.Contains(key)) { value = dictionary[key]; } value.Add(newValue);
你可以定义一个方法来构build一个复合string键,每一个你想要使用字典的地方你都必须使用这个方法来构build你的键,例如:
private string keyBuilder(int key1, int key2) { return string.Format("{0}/{1}", key1, key2); }
使用:
myDict.ContainsKey(keyBuilder(key1, key2))
这也是可能的:
Dictionary<string, string[]> previousAnswers = null;
这样,我们可以拥有唯一的键。 希望这对你有用。
重复键将打破词典的整个合约。 在字典中,每个键都是唯一的,并映射到单个值。 如果你想把一个对象连接到任意数量的附加对象,最好的办法可能就是类似于DataSet(用一般的术语来说)。 把你的钥匙放在一列,你的价值在另一列。 这比字典慢得多,但是这是你失去散列关键对象的能力的折衷。
你可以添加不同的情况下相同的密钥,如:
KEY1
键1
KEY1
KEY1
KEY1
KEY1
我知道是假的答案,但为我工作。