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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With