I'm trying to create a data structure that binds 3 elements together, and where any of the 3 elements can be used as the key.
Up till now, I've been using a bunch of functions that convert from one data element to the corresponding others (i.e. MoveStateToAngle, AngleToMoveState, MoveStateToVector2) but it's extremely ugly and verbose.
Update: The data structure is intended for holding less than 10 entries that will never change.
For such a small number of entries, storing them in a simple array or List<T>
should outperform storing them in dictionaries. So here is my suggestion. It assumes that the types MoveState
, Angle
and Vector2
are already defined:
public class TriDictionary
{
private readonly List<Entry> _entries = new();
public readonly record struct Entry(
MoveState MoveState, Angle Angle, Vector2 Vector2);
public void Add(MoveState moveState, Angle angle, Vector2 vector2)
{
_entries.Add(new(moveState, angle, vector2));
}
public Entry this[MoveState key] => GetEntry(key, static e => e.MoveState);
public Entry this[Angle key] => GetEntry(key, static e => e.Angle);
public Entry this[Vector2 key] => GetEntry(key, static e => e.Vector2);
private Entry GetEntry<TKey>(TKey key, Func<Entry, TKey> keySelector)
{
foreach (Entry entry in _entries)
{
if (keySelector(entry).Equals(key)) return entry;
}
throw new KeyNotFoundException($"Key '{key}' not found.");
}
}
Usage example:
TriDictionary data = new();
//...
data.Add(someMoveState, someAngle, someVector2);
//...
var angle = data[moveState].Angle; // MoveStateToAngle
//...
var moveState = data[angle].MoveState; // AngleToMoveState
//...
var vector2 = data[moveState].Vector2; // MoveStateToVector2
I've avoided using the List<T>.Find
method because it requires that the searched key
is captured in a closure, resulting in needless allocations. That's the reason for the private generic GetEntry<TKey>
method.
For simplicity the implementation above doesn't enforce the uniqueness of the stored keys.