Nut*_*uts 37 .net c# dictionary
是否有可用的字典.NET可以容纳2个键和一个值.喜欢
Dictionary(Of TKey, Of TKey, TValue)
Run Code Online (Sandbox Code Playgroud)
我需要存储两个键,并且在某些时候通过键1来查看项目,而在其他时候通过键2来查看项目.
我目前的解决方案是维护两个词典
Dictionary<string, long> Dict1 = new Dictionary<string, long>();
Dictionary<long, long> Dict2 = new Dictionary<long, long>();
Run Code Online (Sandbox Code Playgroud)
当需要添加项目时,我会将其添加到两个词典中.
Dict1.Add("abc", 111);
Dict2.Add(345, 111);
Run Code Online (Sandbox Code Playgroud)
然后我将从这些字典中的任何一个查找项目,具体取决于我需要查看哪个键.
我在删除或更新项目时也会这样做.
我已经考虑了复合键,但我不知道如何设置它,我不想失去任何搜索项目的速度.
是否有一些解决方案可以.NET拥有可以容纳多个密钥的字典?
Ian*_*ose 13
如果你希望你的价值从任何一个键"可以找到",我只会使用你现在正在做的两个词典.但是我会把它包装在一个类中,方法名称FindByXXX和FindByYYY.
在更难的问题是你怎么做了删除,因为你需要知道删除的时间这两个键.也许您的值存储了两个键,因此您可以将值传递给delete方法.也许你永远不需要从词典中删除项目.或者需要删除项目的代码知道两个密钥.
因此,没有标准字典可以做到这一点,因为每个用户之间的要求是不同的.
(注意,您不希望带有复合键的字典,因为每当您希望查找项目时,您都需要知道这两个键.)
Ale*_*lev 10
也许,这样的事情:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我可以提供第二种解决方案,但与第一种解决方案相比,它看起来更加缓慢和丑陋.
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)));
}
}
Run Code Online (Sandbox Code Playgroud)
在非常糟糕的情况下,当Keys是一个大结构(即大值类型)并且Keys等于大小,并且值是小值类型(例如,一个字节)时,使用第一个解决方案:一组Key1 ,两组Key2,一组值= 3组大对象和1组小值.使用第二种解决方案:一组Key1,一组Key2,一组值= 2组大对象和小组值.即使用第一个解决方案,您需要50%(或更低)的内存空间与第二个相比,但第二个解决方案是非常非常慢的第一个解决方案.
您的解决方案对应用程序的内存占用有很大影响。随着字典的增长,存储实际数据所需的内存量(对于值类型)至少会增加一倍。
你可能可以从不同的角度来解决这个问题。有两本词典:
var lookupDictionary = new Dictionary<string, string>();
var valuesDictionary = new Dictionary<string, [YourValueType]>();
Run Code Online (Sandbox Code Playgroud)
从这里开始,它非常简单。
// 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");
Run Code Online (Sandbox Code Playgroud)
当您需要从valuesDictionary您那里找到某些东西时,请先点击lookupDictionary。这将为您提供您在valuesDictionary.
编辑
我没有在我的回答中解决删除问题,所以在这里:D
你会点击lookupDictionary找到值键,然后删除所有lookupDictionary具有该值的条目。
应该足够简单和安全,因为valuesDictionary它保证有一个唯一的键,因此您不会意外删除某个其他值的查找键。
但是,正如 Ian Ringrose 在评论中指出的那样,您将对lookupDictionary要删除的内容进行全面扫描。这可能会对紧密循环等中的性能产生不良影响。
我暂时想不出解决这个问题的好方法。也许其他人可能对如何改进这一点有一些想法。
我希望这有帮助。
如果您使用的是 C# 7.0,最好的方法是使用元组类型和文字:
// Declare
var dict = new Dictionary<(string, long), long>();
// Add
dict.Add(("abc", 345), 111);
// Get
var searchedValue = dict[("abc", 345)];
Run Code Online (Sandbox Code Playgroud)
您无法仅使用单个字典来完成此操作而不损失查找速度。原因是,如果您要创建复合键,则在重写 GetHashCode 时无法返回有意义的值。这意味着需要对每个键进行相等比较,直到找到字典条目。在这种情况下,复合键还会出现潜在问题:因为您的 Equals 方法会检查一个属性或另一个属性是否相等,所以以下键本质上是重复键 { Id=1, Name="Bob" } { Id=1, Name="Anna" },这并没有给我一种温暖模糊的感觉。
这让你可以用你自己的类包装一个字典或一对字典。