Building on this question, is there a simple solution for having a multi-key dictionary where either key individually can be used to identify the value?
ie.
MultikeyDictionary<TKey1, TKey2, TValue> foo;
foo.Add(key1, key2, value);
myValue = foo[key1];
// value == myValue
foo.Remove(key2);
myValue = foo[key1]; // invalid, Exception or null returned
Sure, it's an OO language and you can implement whatever O's you want. You are going to have some ambiguity to resolve (what if TKey1 and TKey2 are the same type, which methods get called then?)
You won't be able to define the overloads for both types, and the generics system doesn't allow for an arbitrary number of types (like methods allow params). So, you'd be stuck with a set of classes which defined 2, 3, 4, etc. simultaneous keys. Additionally, you'd have to use object as the parameter for get and set, using runtime type checks to simulate the overload.
Additionally, you'd only store one dictionary of
<TKEY1,VAL>
, the other dictionaries would be of<TKEY2,TKEY1>
,<TKEY3,TKEY1>
and would act as indexes on the main dictionary.It's mostly boiler plate code.
I find many answers here unnecessarily complex, less performant or plain unusable. The best approach would be to have a
KeyValuePair<>
of the secondary key and the value clubbed together as theValue
of either dictionaries. This lets you have just one lookup for for removal and updation operations. A straightforward implementation:Few things to note:
I have implemented only
IEnumerable<>
. I don't thinkICollection<>
makes sense here since the method names all could be way different for this special collection structure. Up to you to decide what should go insideIEnumerable<>
.I have attempted for some weird exceptions to be thrown here and there - just for data integrity. Just to be on the safer side so that you know if ever my code has bugs.
I have named methods in such a way that its compilable even when
Key1
andKey2
are of the same type.Performance: You can lookup for
Value
with either of theKey
s.Get
andContains
method require just 1 lookup (O(1)).Add
requires 2 lookups and 2 adds.Update
requires 1 lookup and 2 adds.Remove
takes 3 lookups.