Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有两个键和一个值的.NET字典_C#_.net_Dictionary - Fatal编程技术网

C# 具有两个键和一个值的.NET字典

C# 具有两个键和一个值的.NET字典,c#,.net,dictionary,C#,.net,Dictionary,.NET中是否有可容纳两个键和一个值的词典。 像 我需要存储两个键,有时按键1查看项目,有时按键2查看项目 我目前的解决方案是维护两个字典 Dictionary<string, long> Dict1 = new Dictionary<string, long>(); Dictionary<long, long> Dict2 = new Dictionary<long, long>(); 然后,我将从这些字典中的任何一个中查找一项,这取决于我需要

.NET
中是否有可容纳两个键和一个值的词典。 像

我需要存储两个键,有时按键1查看项目,有时按键2查看项目

我目前的解决方案是维护两个字典

Dictionary<string, long> Dict1 = new Dictionary<string, long>();
Dictionary<long, long> Dict2 = new Dictionary<long, long>();
然后,我将从这些字典中的任何一个中查找一项,这取决于我需要按哪个键查找

删除或更新项目时,我将执行相同的操作

我已经考虑过复合键,但我不知道如何设置它,我不想失去任何搜索项目的速度


.NET
中是否有一些解决方案可以使用可以容纳多个键的字典?

您不能仅使用一个字典而不损失查找速度。原因是,如果要创建复合键,则重写GetHashCode时无法返回有意义的值。这意味着在找到字典条目之前,需要对每个键进行相等性比较。在这种情况下,复合键也可能有一个潜在问题:因为Equals方法会检查一个属性或另一个属性是否相等,所以下面的键本质上是重复键{Id=1,Name=“Bob”}{Id=1,Name=“Anna”},这不会给我一种温暖的模糊感觉


这样,您就可以用自己的类包装一本词典或一对词典。

有趣的问题,这里有一个解决方案。 不过,您必须为要支持的每种键类型添加索引器

public class NewDic<T>
{
    public void Add(string key1, long key2, T value)
    {
        mDic.Add(key1, value);
        mDic.Add(key2, value);
    }

    public T this[string s]
    {
        get { return mDic[s]; }
    }

    public T this[long l]
    {
        get { return mDic[l]; }
    }


    Dictionary<object, T> mDic = new Dictionary<object, T>();
}

        NewDic<long> dic = new NewDic<long>();

        dic.Add("abc", 20, 10);

        Console.WriteLine(dic["abc"]);
        Console.WriteLine(dic[20]);
公共类NewDic
{
公共void Add(字符串键1、长键2、T值)
{
添加(键1,值);
添加(键2,值);
}
公共T此[string s]
{
获取{返回mDic[s];}
}
这是什么
{
获取{返回mDic[l];}
}
Dictionary mDic=新字典();
}
NewDic dic=新的NewDic();
dic.添加(“abc”,第20、10页);
控制台写入线(dic[“abc”]);
控制台写入线(dic[20]);

您的解决方案对应用程序的内存占用有很大影响。随着字典的增长,存储实际数据所需的内存量(对于值类型)将至少增加一倍

你也许可以从另一个角度来看待这个问题。我有两本字典:

var lookupDictionary = new Dictionary<string, string>();
var valuesDictionary = new Dictionary<string, [YourValueType]>();
当您需要从
valuesDictionary
中查找某些内容时,请首先点击
lookupDictionary
。这将为您提供在
valuesDictionary
中查找的值的键

编辑

我在回答中没有提到删除问题,所以这里是:D

您可以点击
lookupDictionary
查找值键,然后从
lookupDictionary
中删除所有具有该值的条目

应该足够简单和安全,因为
valuesDictionary
保证具有唯一的键,因此不会意外删除其他值的查找键

然而,正如Ian Ringrose在评论中指出的那样,您将对
lookupDictionary
进行完整扫描以删除。这可能会对紧循环等的性能产生不良影响

目前我真的想不出一个好办法来解决这个问题。也许其他人会对如何改进这一点有一些想法


我希望这会有所帮助。

因为您希望您的值可以从任意一个键“查找”,所以我将使用两个字典,就像您现在所做的那样但是我会将其封装在一个类中,方法名为
FindByXXX
FindByYYY

更难的问题是如何执行删除,因为在删除时您需要知道两个键。也许您的值存储了两个键,这样您就可以将值传递到delete方法中。也许你永远不需要从字典中删除条目。或者需要删除项的代码知道这两个键

因此,由于每个用户的需求不同,因此没有标准的词典可以做到这一点


(请注意,您不需要具有复合键的词典,因为这需要您在希望查找项目时同时知道这两个键。)

这不是一个合适的词典,但可用于添加或删除功能等简单的词典

通过在键类型中正确实现IComparable,并相应地更改字典代码,也可以使其成为通用的。(注意,不允许使用键的默认值来管理歧义!)

一本
字典怎么样?元组是按值比较的,因此它应该以预期的方式唯一地索引。另外,现在您不必将
long
值打包到两个地方(并且处理在任何地方同步值的奇妙痛苦)

这种方法怎么样?基本上,仍然使用基于字典的策略,但通过一个具有重载索引器属性的类来实现。所以它看起来像一本字典,感觉像一本字典,但支持多个键(不像字典,哈哈)

公共类多键词典
{
专用只读词典firstKeyDictionary=
新字典();
专用只读词典secondKeyDictionary=
新字典();
公共TValue this[TFirstKey idx]
{
得到
{
返回firstKeyDictionary[idx];
}
设置
{
firstKeyDictionary[idx]=值;
}
}
公共TValue this[TSecondKey idx]
{
得到
{
var firstKey=secondKeyDictionary[idx];
返回firstKeyDictionary[firstKey];
}
设置
{
var firstKey=secondKeyDictionary[idx];
firstKeyDictionary[firstKey]=值;
}
}
public IEnumerable GetKeyValuePairsOfFirstKey()
{
public class NewDic<T>
{
    public void Add(string key1, long key2, T value)
    {
        mDic.Add(key1, value);
        mDic.Add(key2, value);
    }

    public T this[string s]
    {
        get { return mDic[s]; }
    }

    public T this[long l]
    {
        get { return mDic[l]; }
    }


    Dictionary<object, T> mDic = new Dictionary<object, T>();
}

        NewDic<long> dic = new NewDic<long>();

        dic.Add("abc", 20, 10);

        Console.WriteLine(dic["abc"]);
        Console.WriteLine(dic[20]);
var lookupDictionary = new Dictionary<string, string>();
var valuesDictionary = new Dictionary<string, [YourValueType]>();
// Add a new entry into the values dictionary and give it a unique key
valuesDictionary.Add("FooBar", "FUBAR VALUE");

// Add any number of lookup keys with the same value key
lookupDictionary.Add("Foo", "FooBar");
lookupDictionary.Add("Bar", "FooBar");
lookupDictionary.Add("Rab", "FooBar");
lookupDictionary.Add("Oof", "FooBar");
internal class KeyValueSet //this dictionary item is tailor made for this example
{
    public string KeyStr { get; set; }
    public int KeyInt { get; set; }
    public int Value { get; set; }

    public KeyValueSet() { }

    public KeyValueSet(string keyStr, int keyInt, int value)
    {
        KeyStr = keyStr;
        KeyInt = keyInt;
        Value = value;
    }
}

public class DoubleKeyDictionary
{
    List<KeyValueSet> _list = new List<KeyValueSet>();

    private void Add(KeyValueSet set)
    {
        if (set == null)
            throw new InvalidOperationException("Cannot add null");
        if (string.IsNullOrEmpty(set.KeyStr) && set.KeyInt == 0)
            throw new InvalidOperationException("Invalid key");
        if (!string.IsNullOrEmpty(set.KeyStr) && _list.Any(l => l.KeyStr.Equals(set.KeyStr))
            || set.KeyInt != 0 && _list.Any(l => l.KeyInt == set.KeyInt))
            throw new InvalidOperationException("Either of keys exists");
        _list.Add(set);
    }

    public void Add(string keyStr, int keyInt, int value)
    {
        Add(new KeyValueSet { KeyInt = keyInt, KeyStr = keyStr, Value = value });
    }

    public void Add(string key, int value)
    {
        Add(new KeyValueSet { KeyInt = 0, KeyStr = key, Value = value });
    }

    public void Add(int key, int value)
    {
        Add(new KeyValueSet { KeyInt = key, KeyStr = string.Empty, Value = value });
    }

    public void Remove(int key)
    {
        if (key == 0)
            throw new InvalidDataException("Key not found");
        var val = _list.First(l => l.KeyInt == key);
        _list.Remove(val);
    }

    public void Remove(string key)
    {
        if (string.IsNullOrEmpty(key))
            throw new InvalidDataException("Key not found");
        var val = _list.First(l => l.KeyStr == key);
        _list.Remove(val);
    }

    public void Remove(KeyValueSet item)
    {
        _list.Remove(item);
    }

    public int this[int index]
    {
        get
        {
            if (index != 0 && _list.Any(l => l.KeyInt == index))
                return _list.First(l => l.KeyInt == index).Value;
            throw new InvalidDataException("Key not found");
        }
        set
        {
            Add(index, value);
        }
    }

    public int this[string key]
    {
        get
        {
            if (!string.IsNullOrEmpty(key) && _list.Any(l => l.KeyStr == key))
                return _list.First(l => l.KeyStr == key).Value;
            throw new InvalidDataException("Key not found");
        }
        set
        {
            Add(key, value);
        }
    }
}
var dict = new DoubleKeyDictionary();
dict.Add(123, 1);
dict.Add(234, 2);
dict.Add("k1", 3);
dict.Add("k2", 4);            
dict[456] = 5;
dict["k3"] = 6;
dict.Add("k4", 567, 7);
dict.Remove(123);

Console.WriteLine(dict[234]); //2
Console.WriteLine(dict["k2"]); //4
Console.WriteLine(dict[456]); //5
Console.WriteLine(dict[567]); //7
Console.WriteLine(dict["k4"]); //7
Console.WriteLine(dict[123]); //exception
public class MultiKeyDictionary<TFirstKey, TSecondKey, TValue>
{
    private readonly Dictionary<TFirstKey, TValue> firstKeyDictionary = 
        new Dictionary<TFirstKey, TValue>();
    private readonly Dictionary<TSecondKey, TFirstKey> secondKeyDictionary = 
        new Dictionary<TSecondKey, TFirstKey>();

    public TValue this[TFirstKey idx]
    {
        get
        {
            return firstKeyDictionary[idx];
        }
        set
        {
            firstKeyDictionary[idx] = value;
        }
    }

    public TValue this[TSecondKey idx]
    {
        get
        {
            var firstKey = secondKeyDictionary[idx];
            return firstKeyDictionary[firstKey];
        }
        set
        {
            var firstKey = secondKeyDictionary[idx];
            firstKeyDictionary[firstKey] = value;
        }
    }

    public IEnumerable<KeyValuePair<TFirstKey, TValue>> GetKeyValuePairsOfFirstKey()
    {
        return firstKeyDictionary.ToList();
    }

    public IEnumerable<KeyValuePair<TSecondKey, TValue>> GetKeyValuePairsOfSecondKey()
    {
        var r = from s in secondKeyDictionary
            join f in firstKeyDictionary on s.Value equals f.Key
            select new KeyValuePair<TSecondKey, TValue>(s.Key, f.Value);

        return r.ToList();
    }

    public void Add(TFirstKey firstKey, TSecondKey secondKey, TValue value)
    {
        firstKeyDictionary.Add(firstKey, value);
        secondKeyDictionary.Add(secondKey, firstKey);
    }

    public bool Remove(TFirstKey firstKey)
    {
        if (!secondKeyDictionary.Any(f => f.Value.Equals(firstKey))) return false;

        var secondKeyToDelete = secondKeyDictionary.First(f => f.Value.Equals(firstKey));

        secondKeyDictionary.Remove(secondKeyToDelete.Key);
        firstKeyDictionary.Remove(firstKey);

        return true;
    }

    public bool Remove(TSecondKey secondKey)
    {
        if (!secondKeyDictionary.ContainsKey(secondKey)) return false;

        var firstKey = secondKeyDictionary[secondKey];
        secondKeyDictionary.Remove(secondKey);
        firstKeyDictionary.Remove(firstKey);

        return true;
    }
}
    static void Main(string[] args)
    {
        var dict = new MultiKeyDictionary<string, long, long>();
        dict.Add("abc", 111, 1234);
        dict.Add("def", 222, 7890);
        dict.Add("hij", 333, 9090);

        Console.WriteLine(dict["abc"]); // expect 1234
        Console.WriteLine(dict["def"]); // expect 7890
        Console.WriteLine(dict[333]); // expect 9090

        Console.WriteLine();
        Console.WriteLine("removing def");
        dict.Remove("def");

        Console.WriteLine();
        Console.WriteLine("now we have:");
        foreach (var d in dict.GetKeyValuePairsOfFirstKey())
        {
            Console.WriteLine($"{d.Key} : {d.Value}");
        }

        Console.WriteLine();
        Console.WriteLine("removing 333");
        dict.Remove(333);

        Console.WriteLine();
        Console.WriteLine("now we have:");
        foreach (var d in dict.GetKeyValuePairsOfSecondKey())
        {
            Console.WriteLine($"{d.Key} : {d.Value}");
        }

        Console.ReadLine();
    }
public class TwoKeyDictionary<Tkey1, Tkey2, TValue>
{
    private object m_data_lock = new object();
    private Dictionary<Tkey1, Tkey2> m_dic1 = new Dictionary<Tkey1, Tkey2>();
    private Dictionary<Tkey2, TValue> m_dic2 = new Dictionary<Tkey2, TValue>();

    public void AddValue(Tkey1 key1, Tkey2 key2, TValue value)
    {
        lock(m_data_lock)
        {
            m_dic1[key1] = key2;
            m_dic2[key2] = value;
        }
    }

    public TValue getByKey1(Tkey1 key1)
    {
        lock(m_data_lock)
            return m_dic2[m_dic1[key1]];
    }

    public TValue getByKey2(Tkey key2)
    {
        lock(m_data_lock)
            return m_dic2[key2];
    }

    public void removeByKey1(Tkey1 key1)
    {
        lock(m_data_lock)
        {
            Tkey2 tmp_key2 =   m_dic1[key1];
            m_dic1.Remove(key1);
            m_dic2.Remove(tmp_key2);
        }
    }

    public void removeByKey2(Tkey2 key2)
    {
        lock(m_data_lock)
        {
            Tkey1 tmp_key1 = m_dic1.First((kvp) => kvp.Value.Equals(key2)).Key;
            m_dic1.Remove(tmp_key1);
            m_dic2.Remove(key2);
        }
    }
}
public class TwoKeysDictionary<K1, K2, V>
{
    private class TwoKeysValue<K1, K2, V>
    {
        public K1 Key1 { get; set; }
        public K2 Key2 { get; set; }
        public V Value { get; set; }
    }

    private List<TwoKeysValue<K1, K2, V>> m_list = new List<TwoKeysValue<K1, K2, V>>();

    public void Add(K1 key1, K2 key2, V value)
    {
        lock (m_list)
            m_list.Add(new TwoKeysValue<K1, K2, V>() { Key1 = key1, Key2 = key2, Value = value });
    }

    public V getByKey1(K1 key1)
    {
        lock (m_list)
            return m_list.First((tkv) => tkv.Key1.Equals(key1)).Value;
    }

    public V getByKey2(K2 key2)
    {
        lock (m_list)
            return m_list.First((tkv) => tkv.Key2.Equals(key2)).Value;
    }

    public void removeByKey1(K1 key1)
    {
        lock (m_list)
            m_list.Remove(m_list.First((tkv) => tkv.Key1.Equals(key1)));
    }

    public void removeByKey2(K2 key2)
    {
        lock (m_list)
            m_list.Remove(m_list.First((tkv) => tkv.Key2.Equals(key2)));
    }
}
Dictionary<Object, long> dict = new Dictionary<Object, long>();
dict.Add("abc", 111);
dict.Add(345, 111);
public void Add(ISet<Object> keys, T value){
    foreach(Object k in keys)
    {
        _privateDict.Add(k, value); 
    }
}
public class StringIntDictionary<TValue> : IDictionary<string, TValue>, IDictionary<int, TValue>
{
    private IDictionary<object, TValue> _dictionary = new Dictionary<object, TValue>();
    // implement interface below, delegate to _dictionary
}
var dict = StringIntDictionary<bool>();
dict["abc"] = true;
dict[123] = true;
public class SPurchaseOption
{
    public Button Button;
    public string ProductID;
    public string SomeOtherAssociatedData;
}

Dictionary<object, SPurchaseOption> purchaseOptions;
Key: ProductID, Value: "SPurchaseOption"
Key: Button,    Value: "SPurchaseOption"
public class DoubleKeyedDictionary<TKey1, TKey2, TValue>
{
    class SItem
    {
        public TKey1 key1;
        public TKey2 key2;
        public TValue value;
    }

    Dictionary<TKey1, SItem> dic1;
    Dictionary<TKey2, SItem> dic2;
}
// Declare
var dict = new Dictionary<(string, long), long>();

// Add
dict.Add(("abc", 345), 111);

// Get
var searchedValue = dict[("abc", 345)];
class MyClass
{
  public string StringKey = "";
  public int IntKey = 0;

  public override Equals(object obj)
  {
    // Code to return true if all fields are equal
  }
}

Dictionary <MyClass, string> MyDict;
MyClass myClass;

MyDict[MyDict.Keys.FirstOrDefault(x => x.Equals(MyClass))];
public class MultiKeyDictionary<TKeyType1, TKeyType2, TValueType>
{
    private readonly object threadLock = new object();
    private readonly Dictionary<TKeyType1, TValueType> _dictionary1 = new Dictionary<TKeyType1, TValueType>();
    private readonly Dictionary<TKeyType2, TValueType> _dictionary2 = new Dictionary<TKeyType2, TValueType>();
    private readonly Dictionary<TKeyType1, TKeyType2> _Key1Key2Map = new Dictionary<TKeyType1, TKeyType2>();
    private readonly Dictionary<TKeyType2, TKeyType1> _Key2Key1Map = new Dictionary<TKeyType2, TKeyType1>();

    public bool Add(TKeyType1 key1, TKeyType2 key2, TValueType v)
    {
        if (ContainsKey1(key1) || ContainsKey2(key2))
            return false;
        _dictionary1.Add(key1, v);
        _dictionary2.Add(key2, v);
        _Key1Key2Map.Add(key1, key2);
        _Key2Key1Map.Add(key2, key1);
        return true;
    }
    public bool ContainsKey1(TKeyType1 key)
    {
        return _dictionary1.ContainsKey(key);
    }
    public bool ContainsKey2(TKeyType2 key)
    {
        return _dictionary2.ContainsKey(key);
    }       
    //Note if TKeyType1 and TKeyType2 are the same then we are forced to use GetBy functions
    public TValueType GetByKey1(TKeyType1 key)
    {
        return _dictionary1[key];
    }
    public TValueType GetByKey2(TKeyType2 key)
    {
        return _dictionary2[key];
    }
    public bool SetByKey1(TKeyType1 key, TValueType val)
    {
        if (ContainsKey1(key))
            return false;
        lock (threadLock)
        {
            var key2 = _Key1Key2Map[key];
            _dictionary1[key] = val;
            _dictionary2[key2] = val;
        }
        return true;
    }
    public bool SetByKey2(TKeyType2 key, TValueType val)
    {
        if (ContainsKey2(key))
            return false;
        lock (threadLock)
        {
            var key1 = _Key2Key1Map[key];
            _dictionary1[key1] = val;
            _dictionary2[key] = val;
        }
        return true;
    }
    public void RemoveUsingKey1(TKeyType1 key)
    {
        lock (threadLock)
        {
            var key2 = _Key1Key2Map[key];
            _dictionary1.Remove(key);
            _dictionary2.Remove(key2);
            _Key1Key2Map.Remove(key);
            _Key2Key1Map.Remove(key2);
        }
    }
    public void RemoveUsingKey2(TKeyType2 key)
    {
        lock (threadLock)
        {
            var key1 = _Key2Key1Map[key];
            _dictionary1.Remove(key1);
            _dictionary2.Remove(key);
            _Key1Key2Map.Remove(key1);
            _Key2Key1Map.Remove(key);
        }
    }
    public bool Contains(TKeyType1 key)
    {
        return _dictionary1.ContainsKey(key);
    }
    public bool Contains(TKeyType2 key)
    {
        return _dictionary2.ContainsKey(key);
    }
    public TValueType this[TKeyType1 key]
    {
        get => GetByKey1(key);
        set => SetByKey1(key, value);
    }
    public TValueType this[TKeyType2 key]
    {
        get => GetByKey2(key);
        set => SetByKey2(key, value);
    }
    public void Remove(TKeyType1 key)
    {
        RemoveUsingKey1(key);
    }
    public void Remove(TKeyType2 key)
    {
        RemoveUsingKey2(key);
    }
    public int Count => _dictionary1.Count;
    public Dictionary<TKeyType1, TValueType>.KeyCollection Key1s => _dictionary1.Keys;
    public Dictionary<TKeyType2, TValueType>.KeyCollection Key2s => _dictionary2.Keys;
    public Dictionary<TKeyType1, TValueType>.ValueCollection Values => _dictionary1.Values;
    public void Clear()
    {
        lock (threadLock)
        {
            _dictionary1.Clear();
            _dictionary2.Clear();
            _Key1Key2Map.Clear();
            _Key2Key1Map.Clear();
        }
    }
    //Map between Keys
    public TKeyType2 Key2(TKeyType1 key)
    {
        return _Key1Key2Map[key];
    }
    public TKeyType1 Key1(TKeyType2 key)
    {
        return _Key2Key1Map[key];
    }
}