字典的键是 List<T>。

3

我在使用List作为Dictionary()的键时遇到了一些问题。下面是一个说明问题的示例代码:

Dictionary<List<double>, string> test = new Dictionary<List<double>, string>();
var a = new List<double>() { 1.0 };
var b = new List<double>() { 2.0 };

test.Add(a, "A");
test.Add(b, "B");

// Works because the reference is the same
Console.WriteLine(test[a]);

// KeyNotFoundException
Console.WriteLine(test[new List<double>() { 1.0 }]);

我知道出现错误的原因是字典正在使用列表的引用而不是列表的内容。如果TKey是一个List,最好使用SequenceEquals来确定键是否存在。

有什么想法可以解决这个问题吗?还有其他可以使用的集合吗?我必须创建一个新的包装类SequenceDictionary吗?


那么为什么你不能在创建实例之前就完成它呢? - evasilchenko
编写您自己的类来实现 IList(使用 List),并重写 EqualsGetHashCode 方法。 - L.B
如果我执行 var c = new List<double>() { 1.0 }; 然后 test[c],异常仍然会被抛出,因为虽然 c={1.0},但是 c 有一个不同的引用。 - Mark
@L.B 这有点过头了,实现一个IEqualityComparer<T>要容易得多,而且Dictionary构造函数有一个重载可以接受它。实现IList<T>真的很烦人。 - RichK
2个回答

4
您需要为字典指定一个自定义比较器。字典构造函数采用了另外一个带有IEqualityComparer<List<double>>参数的重载。然后,您只需要创建一个类,其中包含一个可以比较两个List<double>的Compare方法。您还需要提供一个使用该方法的GetHashCode方法。
另一个选项是找到一个不是列表的键。由于以下几个原因,列表不适合作为键:
- 您无法快速比较两个列表。比较方法的时间复杂度为O(n)。 - 您无法快速计算列表的哈希值;您需要使用列表中的所有项目来构建适当的哈希值。 - 如果列表在字典内部发生更改,则哈希码将发生变化,这将破坏各种东西。只要列表是字典中的键,它就需要是不可变的。

你的意思是IEqualityComparer,而不是Comparer。但除此之外,是的 :) - Jon Skeet

2
要么这样,要么创建一个继承自 List<double> 且实现了 IComparable 接口的自定义关键字类。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接