字符串数组查找字典

3

我正在处理一个包含字符串数组的字典列表。这些字典是通过循环DataTable来定义/填充的。在下面的代码中,test评估为false(两次),有人能告诉我原因吗?

List<Dictionary<string[], int>> mydix = new List<Dictionary<string[], int>>();

mydix.Add(new Dictionary<string[], int>()); 
mydix.Add(new Dictionary<string[], int>()); 
mydix.Add(new Dictionary<string[], int>()); 

string[] s = {"tree"};
mydix[1].Add(s, 1);
bool test = mydix[1].ContainsKey(s); // This evaluates to true, which I understand
var entry= mydix[1][s]; // This is 1

DataTable dt=new DataTable();
dt.Columns.Add("test");
dt.Rows.Add(new string[] {"key"});            
mydix[2].Add(dt.Rows[0].ItemArray.Select(x => x.ToString()).ToArray(), 2);
test = mydix[2].ContainsKey(new string[] { "key" }); // Why does this evaluate to false?

// Here is an example with an array with two elements
DataTable dt2 = new DataTable(); 
dt2.Columns.Add("test");
dt2.Columns.Add("test2");    
string[] t={"tree1","tree2"}; 
dt2.Rows.Add(t);
mydix[0].Add(dt2.Rows[0].ItemArray.Select(x => x.ToString()).ToArray(), 3);
test = mydix[0].ContainsKey(t); // Why does this evaluate to false? 

这篇文章帮助我将哈希函数推广到字符串。 - user2546346
2个回答

1
问题在于你使用的字符串数组作为字典的键是进行对象比较而非内容比较的。 为了支持这种数据类型作为键,最简单的解决方案是使用IEqualityComparer。 首先,创建比较器(以下是示例;你需要进行额外的逻辑检查和验证):
    private class ArrayComparer : IEqualityComparer<string[]>
    {
        public bool Equals(string[] item1, string[] item2)
        {
            if (item1[0] == item2[0])
            {
                return true;
            }
            else
            {
                return false;
            }
        }


        public int GetHashCode(string[] item)
        {
            return item[0].GetHashCode();
        }

然后,更改您的字典实例化以使用这个新的比较器:

    mydix.Add(new Dictionary<string[], int>(new ArrayComparer()));
    mydix.Add(new Dictionary<string[], int>(new ArrayComparer())); 
    mydix.Add(new Dictionary<string[], int>(new ArrayComparer())); 

一旦你完成这个步骤,两个测试都会返回true。

谢谢!这确实解决了我的问题。我还是C#的新手,正如你所看到的,我在对象引用方面有些困难。我现在正在努力将其推广到具有多个元素的字符串数组:<!-- language: c# --> DataTable dt2 = new DataTable(); dt2.Columns.Add("test"); dt2.Columns.Add("test2"); string[] t={"tree1","tree2"}; dt2.Rows.Add(t); mydix[0].Add(dt2.Rows[0].ItemArray.Select(x => x.ToString()).ToArray(), 3); test = mydix[0].ContainsKey(t); // 为什么这个结果是false? - user2546346
我的代码在这个注释中并不容易阅读。我已经在原始帖子中包含了泛化的内容(请参见最后一个示例)。你能帮我解决这个问题吗? 我可以很容易地扩展public bool Equals来检查数组的每个元素,但是如何扩展GetHasCode到item[2]呢? - user2546346

1
希望有人能纠正我,但我理解当你调用ContainsKey时,Dictionary有一个私有方法(在dotPeek中探索),该方法运行以确定要比较的对象是否相等。
根据您用于键的类型,将发生不同的相等性比较,基于IEqualityComparer的各种实现,因此可以根据您希望比较的类型运行最适当的比较。
您正在使用字符串数组作为键,因此您实际上正在检查数组对象本身的相等性,而不是它们的内容。因此,您的ContainsKey返回false是完全正确的,您没有询问Dictionary是否包含与键相同的数组,而是询问它是否包含不同的数组,这些数组恰好包含相同的内容。
在这种情况下(一个数组),IEqualityComparer GetHashCode方法将根据对象的引用而不是内容返回哈希值。
如果您想要这种行为,神奇的Skeet先生在此帖子中为数组编写了自定义的IEqualityComparer :

比较对象?


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