带有两个键和一个值的.NET字典

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

如果你希望你的价值从任何一个键"可以找到",我只会使用你现在正在做的两个词典.但是我会把它包装在一个类中,方法名称FindByXXXFindByYYY.

更难的问题是你怎么做了删除,因为你需要知道删除的时间这两个键.也许您的值存储了两个键,因此您可以将值传递给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%(或更低)的内存空间与第二个相比,但第二个解决方案是非常非常慢的第一个解决方案.

  • @ user2143213,您是否了解值类型和对象类型之间的区别以及对象的存储方式? (2认同)

Ale*_*lex 7

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

你可能可以从不同的角度来解决这个问题。有两本词典:

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要删除的内容进行全面扫描。这可能会对紧密循环等中的性能产生不良影响。

我暂时想不出解决这个问题的好方法。也许其他人可能对如何改进这一点有一些想法。

我希望这有帮助。

  • 你假设 TValue 是一个结构,问题中没有任何内容说它是。 (2认同)

Hüs*_*ğlı 6

如果您使用的是 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)

  • 这很公平,但却违背了我想象的字典的性能目标。 (5认同)

Ana*_*nke 3

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

这让你可以用你自己的类包装一个字典或一对字典。