C# .NET字典中的重复键?

C# .NET字典中的重复键?,c#,.net,dictionary,multimap,C#,.net,Dictionary,Multimap,.NET基类库中是否有允许使用重复键的字典类?我发现的唯一解决方案是创建一个类,例如: Dictionary<string, List<object>> 字典 但实际使用时,这是非常令人恼火的。在Java中,我相信多重映射可以实现这一点,但在.NET中找不到类似的映射。我认为类似于列表的东西可以完成这项工作。重复的键破坏了字典的整个契约。在字典中,每个键都是唯一的,并映射到单个值。如果您想将一个对象链接到任意数量的其他对象,最好的选择可能是类似于数据集的东西(通常的说

.NET基类库中是否有允许使用重复键的字典类?我发现的唯一解决方案是创建一个类,例如:

Dictionary<string, List<object>>
字典

但实际使用时,这是非常令人恼火的。在Java中,我相信多重映射可以实现这一点,但在.NET中找不到类似的映射。

我认为类似于
列表的东西可以完成这项工作。

重复的键破坏了字典的整个契约。在字典中,每个键都是唯一的,并映射到单个值。如果您想将一个对象链接到任意数量的其他对象,最好的选择可能是类似于数据集的东西(通常的说法是表)。将键放在一列中,将值放在另一列中。这比字典要慢得多,但这是您失去散列键对象能力的折衷办法

你的意思是一致的而不是实际的重复?否则哈希表将无法工作

同余意味着两个单独的键可以散列为相等的值,但键不相等

例如:假设您的哈希表的哈希函数只是hashval=key mod 3。1和4都映射为1,但值不同。这就是你关于列表的想法发挥作用的地方

当需要查找1时,该值将散列为1,遍历列表直到找到Key=1


如果允许插入重复的键,则无法区分哪些键映射到哪些值。

如果同时使用字符串作为键和值,则可以使用,它将通过GetValues(string key)方法返回一个字符串值数组。

我刚刚看到一个库,其中包括,其中包括一个名为MultiDictionary的类。这巧妙地包装了这种类型的功能。

NameValueCollection在一个键(也是一个字符串)下支持多个字符串值,但这是我所知道的唯一示例


当我遇到需要这种功能的情况时,我倾向于创建类似于您示例中的结构

如果您使用的是.NET3.5,请使用该类

编辑:通常使用创建
查找
。这确实假设您以后不需要更改它-但我通常认为这已经足够好了


如果这对您不起作用,我认为框架中没有任何东西可以帮助您-使用字典是最好的:(

关于使用查找的非常重要的注意事项:

您可以通过在实现
IEnumerable(T)

没有公共构造函数来创建
Lookup(TKey,TElement)
的新实例。此外,
Lookup(TKey,TElement)
对象是不可变的,也就是说,在创建
Lookup(TKey,TElement)
对象之后,您不能添加或删除该对象中的元素或键


我认为这对于大多数用途来说都是一个阻碍因素。

对于包含重复项的键/值集合,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 List=新列表();
//在此处向集合添加一些值
for(int i=0;i
回答原始问题。类似于
字典
的内容在
代码项目
中名为
MultiMap
的类中实现

您可以通过以下链接找到更多信息:

我在搜索同一个答案时偶然发现了这篇文章,但没有找到任何答案,因此我使用字典列表构建了一个简单的示例解决方案,覆盖[]操作符,在所有其他字典都具有给定键(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;
            }
        }
    }
DKD级{
列出字典;
公共DKD(){
字典=新列表();}
公共对象此[字符串键]{
得到{
字符串温度;
列表值列表=新列表();
for(int i=0;i
使用
列表
选项时,可以使用LINQ进行搜索:

List myList=new List();
//在这里填
var q=从myList中的a.Key.Equals(“somevalue”)中选择a.Value
如果(q.Count()>0){//您已经得到了您的值}

下面是使用List>

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);
}
具有重复项的公共类列表:列表
{
公共void添加(字符串键、字符串值)
{
var元素=新的KeyValuePair(键,值);
添加(元素);
}
}
var list=新的ListWithDuplicates();
添加(“k1”、“v1”);
添加(“k1”、“v2”);
添加(“k1”、“v3”);
foreach(列表中的变量项)
{
字符串x=string.format(“{0}={1},”,item.Key,item.Value);
}

输出k1=v1,k1=v2,k1=v3

我使用的方法只是

字典

这样,您就有了一个包含字符串列表的单键

例如:

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<string> value = new List<string>();
if (dictionary.Contains(key)) {
     value = dictionary[key];
}
value.Add(newValue);
列表值=新列表();
if(dictionary.Contains(key)){
值=字典[键];
}
value.Add(newValue);
// 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());
}
Dictionary<string, string[]> previousAnswers = null;
private string keyBuilder(int key1, int key2)
{
    return string.Format("{0}/{1}", key1, key2);
}
myDict.ContainsKey(keyBuilder(key1, key2))
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));
}
public class HashMapDictionary<T1, T2> : System.Collections.IEnumerable
{
    private System.Collections.Concurrent.ConcurrentDictionary<T1, List<T2>> _keyValue = new System.Collections.Concurrent.ConcurrentDictionary<T1, List<T2>>();
    private System.Collections.Concurrent.ConcurrentDictionary<T2, List<T1>> _valueKey = new System.Collections.Concurrent.ConcurrentDictionary<T2, List<T1>>();

    public ICollection<T1> Keys
    {
        get
        {
            return _keyValue.Keys;
        }
    }

    public ICollection<T2> Values
    {
        get
        {
            return _valueKey.Keys;
        }
    }

    public int Count
    {
        get
        {
            return _keyValue.Count;
        }
    }

    public bool IsReadOnly
    {
        get
        {
            return false;
        }
    }

    public List<T2> this[T1 index]
    {
        get { return _keyValue[index]; }
        set { _keyValue[index] = value; }
    }

    public List<T1> this[T2 index]
    {
        get { return _valueKey[index]; }
        set { _valueKey[index] = value; }
    }

    public void Add(T1 key, T2 value)
    {
        lock (this)
        {
            if (!_keyValue.TryGetValue(key, out List<T2> result))
                _keyValue.TryAdd(key, new List<T2>() { value });
            else if (!result.Contains(value))
                result.Add(value);

            if (!_valueKey.TryGetValue(value, out List<T1> result2))
                _valueKey.TryAdd(value, new List<T1>() { key });
            else if (!result2.Contains(key))
                result2.Add(key);
        }
    }

    public bool TryGetValues(T1 key, out List<T2> value)
    {
        return _keyValue.TryGetValue(key, out value);
    }

    public bool TryGetKeys(T2 value, out List<T1> key)
    {
        return _valueKey.TryGetValue(value, out key);
    }

    public bool ContainsKey(T1 key)
    {
        return _keyValue.ContainsKey(key);
    }

    public bool ContainsValue(T2 value)
    {
        return _valueKey.ContainsKey(value);
    }

    public void Remove(T1 key)
    {
        lock (this)
        {
            if (_keyValue.TryRemove(key, out List<T2> values))
            {
                foreach (var item in values)
                {
                    var remove2 = _valueKey.TryRemove(item, out List<T1> keys);
                }
            }
        }
    }

    public void Remove(T2 value)
    {
        lock (this)
        {
            if (_valueKey.TryRemove(value, out List<T1> keys))
            {
                foreach (var item in keys)
                {
                    var remove2 = _keyValue.TryRemove(item, out List<T2> values);
                }
            }
        }
    }

    public void Clear()
    {
        _keyValue.Clear();
        _valueKey.Clear();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _keyValue.GetEnumerator();
    }
}
public class TestA
{
    public int MyProperty { get; set; }
}

public class TestB
{
    public int MyProperty { get; set; }
}

            HashMapDictionary<TestA, TestB> hashMapDictionary = new HashMapDictionary<TestA, TestB>();

            var a = new TestA() { MyProperty = 9999 };
            var b = new TestB() { MyProperty = 60 };
            var b2 = new TestB() { MyProperty = 5 };
            hashMapDictionary.Add(a, b);
            hashMapDictionary.Add(a, b2);
            hashMapDictionary.TryGetValues(a, out List<TestB> result);
            foreach (var item in result)
            {
                //do something
            }
  public static class ListWithDuplicateExtensions
  {
    public static void Add<TKey, TValue>(this List<KeyValuePair<TKey, TValue>> collection, TKey key, TValue value)
    {
      var element = new KeyValuePair<TKey, TValue>(key, value);
      collection.Add(element);
    }

    public static int TryGetValue<TKey, TValue>(this List<KeyValuePair<TKey, TValue>> collection, TKey key, out IEnumerable<TValue> values)
    {
      values = collection.Where(pair => pair.Key.Equals(key)).Select(pair => pair.Value);
      return values.Count();
    }
  }
public class ListMap<T,V> : List<KeyValuePair<T, V>>
{
    public void Add(T key, V value) {
        Add(new KeyValuePair<T, V>(key, value));
    }

    public List<V> Get(T key) {
        return FindAll(p => p.Key.Equals(key)).ConvertAll(p=> p.Value);
    }
}
var fruits = new ListMap<int, string>();
fruits.Add(1, "apple");
fruits.Add(1, "orange");
var c = fruits.Get(1).Count; //c = 2;
/// <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 }
var duplicatedDictionaryExample = new List<(string Key, string Value)> { ("", "") ... }
foreach(var entry in duplicatedDictionaryExample)
{ 
    // do something with the values
    entry.Key;
    entry.Value;
}