我想补充一下上面的答案,在某些情况下(取决于数据的分布方式),嵌套字典在内存占用方面比复合键字典好得多(这反过来可能会带来更好的性能总体)。这样做的原因是嵌套可以节省您为键保存重复值的需要,这在大型字典中将使额外字典的占用空间可以忽略不计。
例如,假设我需要一个具有(男/女)、(婴儿/年轻/老人)、(年龄)复合键的字典。
让我们用复合键字典保存一些值:
(male, baby, 1)
(male, baby, 2)
(male, baby, 3)
(male, young, 21)
(male, young, 22)
(male, young, 23)
(male, old, 91)
(male, old, 92)
(male, old, 93)
(female, baby, 1)
(female, baby, 2)
(female, baby, 3)
(female, young, 21)
(female, young, 22)
(female, young, 23)
(female, old, 91)
(female, old, 92)
(female, old, 93)
现在让我们将相同的值保存在字典字典中:
male -> baby -> 1
2
3
young -> 21
22
23
old -> 91
92
93
female -> baby ->1
2
3
young -> 21
22
23
old -> 91
92
93
在复合键方法中,我将“男性”和“女性”的副本保存了 9 次,而不是字典中的单个副本。事实上,我保存了 54 项和 26 项,内存占用量增加了一倍。该示例还有助于可视化差异,查看第二个样本与第一个样本相比有多少“空白”空间,这些都是我们不需要保存的值。
对于那些仍然不相信的人,这里有一个示例测试:
Dictionary<Tuple<int, int, int>, int> map1 = new Dictionary<Tuple<int, int, int>, int>();
Dictionary<int, Dictionary<int, Dictionary<int, int>>> map2 = new Dictionary<int, Dictionary<int, Dictionary<int, int>>>();
public void SizeTest()
{
for (int x = 0; x < 30; x++)
{
for (int y = 0; y < 100; y++)
{
for (int z = 0; z < 600; z++)
{
addToMap1(x, y, z, 0);
addToMap2(x, y, z, 0);
}
}
}
int size1 = GetObjectSize(map1);
int size2 = GetObjectSize(map2);
Console.WriteLine(size1);
Console.WriteLine(size2);
}
private void addToMap1(int x, int y, int z, int value)
{
map1.Add(new Tuple<int, int, int>(x, y, z), value);
}
private void addToMap2(int x, int y, int z, int value)
{
map2.GetOrAdd(x, _ => new Dictionary<int, Dictionary<int, int>>())
.GetOrAdd(y, _ => new Dictionary<int, int>())
.GetOrAdd(z, _ => value);
}
private int GetObjectSize(object TestObject)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
byte[] Array;
bf.Serialize(ms, TestObject);
Array = ms.ToArray();
return Array.Length;
}
public static TResult GetOrAdd<TKey, TResult>(this Dictionary<TKey, TResult> map, TKey key, Func<TKey, TResult> addIfMissing)
{
TResult result;
if (!map.TryGetValue(key, out result))
{
result = addIfMissing(key);
map[key] = result;
}
return result;
}
此测试返回 ~30MB 与 ~70MB 支持字典字典。