Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compound key for dictionaries in .NET

Tags:

c#

.net

vb.net

Dictionary<TKey, TValue> is great for doing fast lookups using the strongly-typed key; sometimes, however, I need to do lookups based on a unique combination of two (or more) variables. My "design pattern" for accomplishing this is to concatenate the values together using a separator, like this:

String compoundKey = productID.ToString + "~" + colorID.ToString;
myDict.Add(compoundKey, myObject);

This method seems a bit hacky. This answer uses a struct but I'm not convinced that it is any better.

What is the preferable way of making dictionaries work with compound keys?

like image 602
poke Avatar asked Feb 21 '14 01:02

poke


2 Answers

If your key is made up of two parts, the most obvious solution is a variable which has two parts. The "classical" way to produce this is a struct:

struct MyKey {
    public string PartA;
    public string PartB;
}

.NET will hash both fields for Dictionary<MyKey, object>. It's better to use a struct, not a class, because by default the identity of a class is defined by where the reference points (similar to the concept of pointers in C or C++) and not the values of the fields. You can, of course, override the Object.GetHashCode method in your class - but it's less work to just use a struct.

In practice, .NET already has a convenience for such situations: A struct with 2 fields can be represented as a Tuple<string, string>. You can then define:

var d = new Dictionary<Tuple<string, string>, object>

And you will index with d[new Tuple<string, string>("some value", "some other value")>].

This looks a bit bulky, so you can add using MyKey = System.Tuple<string, string> to the beginning of your .cs file. Then you will be able to index with d[new MyKey("some value", "some other value")]. The using a = b notation acts as a compile time search and replace.

like image 162
Superbest Avatar answered Sep 23 '22 05:09

Superbest


What is the preferable way of making dictionaries working with compound keys?

My preferred method is to make a custom immutable class for the Key type. This requires a bit of work, but is very clean and clear, and works for any combination of types.

You can also customize the GetHashCode and equality computations if required, as well.


If you're using string or types that properly implement hashing and equality, you can use a Tuple<T1,T2>. If the values within your compound type are more complex, or you need custom equality/hashing (ie: only compare off an ID within an entity object instead of the all properties), a custom class allows you full control over how the equality and hashing are determined for your keys.

like image 28
Reed Copsey Avatar answered Sep 20 '22 05:09

Reed Copsey