.NET基类库中是否存在允许使用重复键的字典类?我找到的唯一解决方案是创建,例如,一个类:
Dictionary<string, List<object>>
但实际上用起来很烦人。在Java中,我相信MultiMap可以实现这一点,但在. net中找不到类似的东西。
.NET基类库中是否存在允许使用重复键的字典类?我找到的唯一解决方案是创建,例如,一个类:
Dictionary<string, List<object>>
但实际上用起来很烦人。在Java中,我相信MultiMap可以实现这一点,但在. net中找不到类似的东西。
当前回答
我用的方法是
词典<弦,弦List < > >
这样,您就有一个键保存一个字符串列表。
例子:
List<string> value = new List<string>();
if (dictionary.Contains(key)) {
value = dictionary[key];
}
value.Add(newValue);
其他回答
由于新的c#(我相信它是从7.0开始的),你也可以做这样的事情:
var duplicatedDictionaryExample = new List<(string Key, string Value)> { ("", "") ... }
你使用它作为一个标准的列表,但有两个值命名为任何你想
foreach(var entry in duplicatedDictionaryExample)
{
// do something with the values
entry.Key;
entry.Value;
}
如果你使用的是。net 3.5,使用Lookup类。
编辑:通常使用Enumerable.ToLookup创建Lookup。这确实假设你不需要更改它之后-但我通常发现这已经足够好了。
如果这对你不起作用,我不认为框架中有任何东西可以帮助-使用字典是最好的:(
你可以创建自己的字典包装器,就像这样,作为奖励,它支持空值作为键:
/// <summary>
/// Dictionary which supports duplicates and null entries
/// </summary>
/// <typeparam name="TKey">Type of key</typeparam>
/// <typeparam name="TValue">Type of items</typeparam>
public class OpenDictionary<TKey, TValue>
{
private readonly Lazy<List<TValue>> _nullStorage = new Lazy<List<TValue>>(
() => new List<TValue>());
private readonly Dictionary<TKey, List<TValue>> _innerDictionary =
new Dictionary<TKey, List<TValue>>();
/// <summary>
/// Get all entries
/// </summary>
public IEnumerable<TValue> Values =>
_innerDictionary.Values
.SelectMany(x => x)
.Concat(_nullStorage.Value);
/// <summary>
/// Add an item
/// </summary>
public OpenDictionary<TKey, TValue> Add(TKey key, TValue item)
{
if (ReferenceEquals(key, null))
_nullStorage.Value.Add(item);
else
{
if (!_innerDictionary.ContainsKey(key))
_innerDictionary.Add(key, new List<TValue>());
_innerDictionary[key].Add(item);
}
return this;
}
/// <summary>
/// Remove an entry by key
/// </summary>
public OpenDictionary<TKey, TValue> RemoveEntryByKey(TKey key, TValue entry)
{
if (ReferenceEquals(key, null))
{
int targetIdx = _nullStorage.Value.FindIndex(x => x.Equals(entry));
if (targetIdx < 0)
return this;
_nullStorage.Value.RemoveAt(targetIdx);
}
else
{
if (!_innerDictionary.ContainsKey(key))
return this;
List<TValue> targetChain = _innerDictionary[key];
if (targetChain.Count == 0)
return this;
int targetIdx = targetChain.FindIndex(x => x.Equals(entry));
if (targetIdx < 0)
return this;
targetChain.RemoveAt(targetIdx);
}
return this;
}
/// <summary>
/// Remove all entries by key
/// </summary>
public OpenDictionary<TKey, TValue> RemoveAllEntriesByKey(TKey key)
{
if (ReferenceEquals(key, null))
{
if (_nullStorage.IsValueCreated)
_nullStorage.Value.Clear();
}
else
{
if (_innerDictionary.ContainsKey(key))
_innerDictionary[key].Clear();
}
return this;
}
/// <summary>
/// Try get entries by key
/// </summary>
public bool TryGetEntries(TKey key, out IReadOnlyList<TValue> entries)
{
entries = null;
if (ReferenceEquals(key, null))
{
if (_nullStorage.IsValueCreated)
{
entries = _nullStorage.Value;
return true;
}
else return false;
}
else
{
if (_innerDictionary.ContainsKey(key))
{
entries = _innerDictionary[key];
return true;
}
else return false;
}
}
}
用法示例:
var dictionary = new OpenDictionary<string, int>();
dictionary.Add("1", 1);
// The next line won't throw an exception;
dictionary.Add("1", 2);
dictionary.TryGetEntries("1", out List<int> result);
// result is { 1, 2 }
dictionary.Add(null, 42);
dictionary.Add(null, 24);
dictionary.TryGetEntries(null, out List<int> result);
// result is { 42, 24 }
关于使用Lookup的非常重要的注意事项:
你可以通过调用一个实现IEnumerable(T)的对象上的Lookup(TKey, TElement)实例来创建一个Lookup(TKey, TElement)实例。
没有公共构造函数来创建Lookup(TKey、TElement)的新实例。此外,Lookup(TKey, TElement)对象是不可变的,也就是说,在创建Lookup(TKey, TElement)对象后,您不能从它添加或删除元素或键。
(从MSDN)
我认为这对大多数人来说都是一种阻碍。
这里有一种方法,用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