Composite Key Dictionary

后端 未结 9 488
心在旅途
心在旅途 2020-12-02 10:18

I have some objects in List, let\'s say List and MyClass has several properties. I would like to create an index of the list based on 3 properti

相关标签:
9条回答
  • 2020-12-02 10:50

    Two approaches immediately spring to mind:

    1. Do as Kevin suggested and write a struct that will serve as your key. Be sure to make this struct implement IEquatable<TKey> and to override its Equals and GetHashCode methods*.

    2. Write a class that utilizes nested dictionaries internally. Something like: TripleKeyDictionary<TKey1, TKey2, TKey3, TValue>... this class would internally have a member of type Dictionary<TKey1, Dictionary<TKey2, Dictionary<TKey3, TValue>>>, and would expose methods such as this[TKey1 k1, TKey2 k2, TKey3 k3], ContainsKeys(TKey1 k1, TKey2 k2, TKey3 k3), etc.

    *A word on whether overriding the Equals method is necessary: while it's true that the Equals method for a struct compares the value of each member by default, it does so by using reflection -- which inherently entails performance costs -- and is therefore not a very appropriate implementation for something that is meant to be used as a key in a dictionary (in my opinion, anyway). According to the MSDN documentation on ValueType.Equals:

    The default implementation of the Equals method uses reflection to compare the corresponding fields of obj and this instance. Override the Equals method for a particular type to improve the performance of the method and more closely represent the concept of equality for the type.

    0 讨论(0)
  • 2020-12-02 10:55

    May I suggest an alternative - a anonymous object. It's the same we use in GroupBy LINQ method with multiple keys.

    var dictionary = new Dictionary<object, string> ();
    dictionary[new { a = 1, b = 2 }] = "value";
    

    It may looks strange, but I've benchmarked Tuple.GetHashCode and new{ a = 1, b = 2 }.GetHashCode methods and the anonymous objects wins on my machine on .NET 4.5.1:

    Object - 89,1732 ms for 10000 calls in 1000 cycles

    Tuple - 738,4475 ms for 10000 calls in 1000 cycles

    0 讨论(0)
  • 2020-12-02 11:05

    The best way I could think of is to create a CompositeKey struct and make sure to override the GetHashCode() and Equals() methods in order to ensure speed and accuracy when working with the collection:

    class Program
    {
        static void Main(string[] args)
        {
            DateTime firstTimestamp = DateTime.Now;
            DateTime secondTimestamp = firstTimestamp.AddDays(1);
    
            /* begin composite key dictionary populate */
            Dictionary<CompositeKey, string> compositeKeyDictionary = new Dictionary<CompositeKey, string>();
    
            CompositeKey compositeKey1 = new CompositeKey();
            compositeKey1.Int1 = 11;
            compositeKey1.Int2 = 304;
            compositeKey1.DateTime = firstTimestamp;
    
            compositeKeyDictionary[compositeKey1] = "FirstObject";
    
            CompositeKey compositeKey2 = new CompositeKey();
            compositeKey2.Int1 = 12;
            compositeKey2.Int2 = 9852;
            compositeKey2.DateTime = secondTimestamp;
    
            compositeKeyDictionary[compositeKey2] = "SecondObject";
            /* end composite key dictionary populate */
    
            /* begin composite key dictionary lookup */
            CompositeKey compositeKeyLookup1 = new CompositeKey();
            compositeKeyLookup1.Int1 = 11;
            compositeKeyLookup1.Int2 = 304;
            compositeKeyLookup1.DateTime = firstTimestamp;
    
            Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup1]);
    
            CompositeKey compositeKeyLookup2 = new CompositeKey();
            compositeKeyLookup2.Int1 = 12;
            compositeKeyLookup2.Int2 = 9852;
            compositeKeyLookup2.DateTime = secondTimestamp;
    
            Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup2]);
            /* end composite key dictionary lookup */
        }
    
        struct CompositeKey
        {
            public int Int1 { get; set; }
            public int Int2 { get; set; }
            public DateTime DateTime { get; set; }
    
            public override int GetHashCode()
            {
                return Int1.GetHashCode() ^ Int2.GetHashCode() ^ DateTime.GetHashCode();
            }
    
            public override bool Equals(object obj)
            {
                if (obj is CompositeKey)
                {
                    CompositeKey compositeKey = (CompositeKey)obj;
    
                    return ((this.Int1 == compositeKey.Int1) &&
                            (this.Int2 == compositeKey.Int2) &&
                            (this.DateTime == compositeKey.DateTime));
                }
    
                return false;
            }
        }
    }
    

    An MSDN article on GetHashCode():

    http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

    0 讨论(0)
提交回复
热议问题