Given that you're looking for a partial match on the key, you're not going to be able to accomplish this with a single dictionary. Here's why:
Suppose you've got some sort of "rule" class. We'll call it "Key". You might instantiate it like this:
Key.Create(0) // this "rule" would match any query key starting with 0 (e.g., {0}, {0, 1}, or {0, 1, 9, 2, 23, 243})
Now suppose you want to query it using some sort of "fact" or "query key" class. Since you query a dictionary using the type of value that was used as the key during the Add operation, you would have to reuse the same type:
Key.Create(0, 2, 13) // this fact should be matched by rules {0}, {0,2} or {0, 2, 13}
Now you're going to attempt to get the value:
var value = map[Key.Create(0, 2, 13)]
The Key class could override Equals to allow partial-key matching. However, the dictionary is going to use the hashcode first, and the hashcode for Key.Create(0, 2, 13) is never going to match the hascode for Key.Create(0). You won't be able to get around this by using any sort of base/derived type either.
The best option would probably be to roll your own class. Something like this should do:
class ResultMap
{
public void Add(int[] key, string value)
{
Debug.Assert(key != null);
Debug.Assert(key.Length > 0);
var currentMap = _root;
foreach (var i in key.Take(key.Length - 1))
{
object levelValue;
if (currentMap.TryGetValue(i, out levelValue))
{
currentMap = levelValue as Dictionary<int, object>;
if (currentMap == null)
throw new Exception("A rule is already defined for this key.");
}
else
{
var newMap = new Dictionary<int, object>();
currentMap.Add(i, newMap);
currentMap = newMap;
}
}
var leaf = key[key.Length - 1];
if (currentMap.ContainsKey(leaf))
throw new Exception("A rule is already defined for this key.");
currentMap.Add(leaf, value);
}
public string TryGetValue(params int[] key)
{
Debug.Assert(key != null);
Debug.Assert(key.Length > 0);
var currentMap = _root;
foreach (var i in key)
{
object levelValue;
if (!currentMap.TryGetValue(i, out levelValue))
return null;
currentMap = levelValue as Dictionary<int, object>;
if (currentMap == null)
return (string) levelValue;
}
return null;
}
private readonly Dictionary<int, object> _root = new Dictionary<int, object>();
}
Here's a unit test:
public void Test()
{
var resultMap = new ResultMap();
resultMap.Add(new[] {0}, "a0");
resultMap.Add(new[] {1, 0}, "b0");
resultMap.Add(new[] {1, 1, 0}, "c0");
resultMap.Add(new[] {1, 1, 1}, "c1");
resultMap.Add(new[] {1, 2}, "b2");
resultMap.Add(new[] {2}, "a2");
Debug.Assert("a0" == resultMap.TryGetValue(0));
Debug.Assert("a0" == resultMap.TryGetValue(0, 0));
Debug.Assert("a0" == resultMap.TryGetValue(0, 1));
Debug.Assert("a0" == resultMap.TryGetValue(0, 2));
Debug.Assert("a0" == resultMap.TryGetValue(0, 0, 0));
Debug.Assert("a0" == resultMap.TryGetValue(0, 0, 1));
Debug.Assert("a0" == resultMap.TryGetValue(0, 0, 2));
Debug.Assert("a0" == resultMap.TryGetValue(0, 1, 0));
Debug.Assert("a0" == resultMap.TryGetValue(0, 1, 1));
Debug.Assert("a0" == resultMap.TryGetValue(0, 1, 2));
Debug.Assert("a0" == resultMap.TryGetValue(0, 2, 0));
Debug.Assert("a0" == resultMap.TryGetValue(0, 2, 1));
Debug.Assert("a0" == resultMap.TryGetValue(0, 2, 2));
Debug.Assert(null == resultMap.TryGetValue(1));
Debug.Assert("b0" == resultMap.TryGetValue(1, 0));
Debug.Assert(null == resultMap.TryGetValue(1, 1));
Debug.Assert("b2" == resultMap.TryGetValue(1, 2));
Debug.Assert("b0" == resultMap.TryGetValue(1, 0, 0));
Debug.Assert("b0" == resultMap.TryGetValue(1, 0, 1));
Debug.Assert("b0" == resultMap.TryGetValue(1, 0, 2));
Debug.Assert("c0" == resultMap.TryGetValue(1, 1, 0));
Debug.Assert("c1" == resultMap.TryGetValue(1, 1, 1));
Debug.Assert(null == resultMap.TryGetValue(1, 1, 2));
Debug.Assert("b2" == resultMap.TryGetValue(1, 2, 0));
Debug.Assert("b2" == resultMap.TryGetValue(1, 2, 1));
Debug.Assert("b2" == resultMap.TryGetValue(1, 2, 2));
Debug.Assert("a2" == resultMap.TryGetValue(2));
Debug.Assert("a2" == resultMap.TryGetValue(2, 0));
Debug.Assert("a2" == resultMap.TryGetValue(2, 1));
Debug.Assert("a2" == resultMap.TryGetValue(2, 2));
Debug.Assert("a2" == resultMap.TryGetValue(2, 0, 0));
Debug.Assert("a2" == resultMap.TryGetValue(2, 0, 1));
Debug.Assert("a2" == resultMap.TryGetValue(2, 0, 2));
Debug.Assert("a2" == resultMap.TryGetValue(2, 1, 0));
Debug.Assert("a2" == resultMap.TryGetValue(2, 1, 1));
Debug.Assert("a2" == resultMap.TryGetValue(2, 1, 2));
Debug.Assert("a2" == resultMap.TryGetValue(2, 2, 0));
Debug.Assert("a2" == resultMap.TryGetValue(2, 2, 1));
Debug.Assert("a2" == resultMap.TryGetValue(2, 2, 2));
}