したがって、これは正確に3つのキーで機能するものです。リストされたパターンに従って、4、5、6などのキー用に1つ作成できます。それは多くのコードになりますが、特に難しい作業ではありません(退屈なだけです)。
キーの各部分に辞書があるため、かなりのメモリを消費することに注意してください。これは、任意のキーからの非常に事実に基づくアクセスの柔軟性に対して支払う代償です。
public class MultiKeyDictionary<T1, T2, T3>
{
private Dictionary<T1, Tuple<T1, T2, T3>> firstLookup = new Dictionary<T1, Tuple<T1, T2, T3>>();
private Dictionary<T2, Tuple<T1, T2, T3>> secondLookup = new Dictionary<T2, Tuple<T1, T2, T3>>();
private Dictionary<T3, Tuple<T1, T2, T3>> thirdLookup = new Dictionary<T3, Tuple<T1, T2, T3>>();
public void Add(Tuple<T1, T2, T3> values)
{
if (!firstLookup.ContainsKey(values.Item1) &&
!secondLookup.ContainsKey(values.Item2) &&
!thirdLookup.ContainsKey(values.Item3))
{
firstLookup.Add(values.Item1, values);
secondLookup.Add(values.Item2, values);
thirdLookup.Add(values.Item3, values);
}
else
{
//throw an exeption or something.
}
}
public Tuple<T1, T2, T3> GetFirst(T1 key)
{
return firstLookup[key];
}
public Tuple<T1, T2, T3> GetSecond(T2 key)
{
return secondLookup[key];
}
public Tuple<T1, T2, T3> GetThird(T3 key)
{
return thirdLookup[key];
}
public void RemoveFirst(T1 key)
{
var values = GetFirst(key);
firstLookup.Remove(values.Item1);
secondLookup.Remove(values.Item2);
thirdLookup.Remove(values.Item3);
}
public void RemoveSecond(T2 key)
{
var values = GetSecond(key);
firstLookup.Remove(values.Item1);
secondLookup.Remove(values.Item2);
thirdLookup.Remove(values.Item3);
}
public void RemoveThird(T3 key)
{
var values = GetThird(key);
firstLookup.Remove(values.Item1);
secondLookup.Remove(values.Item2);
thirdLookup.Remove(values.Item3);
}
}
以下は、まったく異なるアプローチです。各キーのルックアップを設定する代わりに、すべての値を1つのコレクションに格納し、線形検索を実行して特定のキーのアイテムを検索します。O(n)の検索/削除時間はありますが、O(1)の追加です。以前の実装では、O(1)の追加、削除、および検索が行われますが、それを行うにはより多くのメモリが必要になります。
public class MultiKeyDictionary2<T1, T2, T3>
{
private HashSet<Tuple<T1, T2, T3>> lookup = new HashSet<Tuple<T1, T2, T3>>();
private HashSet<T1> firstKeys = new HashSet<T1>();
private HashSet<T2> secondKeys = new HashSet<T2>();
private HashSet<T3> thirdKeys = new HashSet<T3>();
public void Add(Tuple<T1, T2, T3> values)
{
if (lookup.Any(multiKey => object.Equals(multiKey.Item1, values.Item1) ||
object.Equals(multiKey.Item2, values.Item2) ||
object.Equals(multiKey.Item3, values.Item3)))
{
//throw an exception or something
}
else
{
lookup.Add(values);
}
}
public Tuple<T1, T2, T3> GetFirst(T1 key)
{
return lookup.FirstOrDefault(values => object.Equals(values.Item1, key));
}
public Tuple<T1, T2, T3> GetSecond(T2 key)
{
return lookup.FirstOrDefault(values => object.Equals(values.Item2, key));
}
public Tuple<T1, T2, T3> GetThird(T3 key)
{
return lookup.FirstOrDefault(values => object.Equals(values.Item3, key));
}
public void RemoveFirst(T1 key)
{
var values = GetFirst(key);
if (values != null)
lookup.Remove(values);
}
public void RemoveSecond(T2 key)
{
var values = GetSecond(key);
if (values != null)
lookup.Remove(values);
}
public void RemoveThird(T3 key)
{
var values = GetThird(key);
if (values != null)
lookup.Remove(values);
}
}