testing在c#中的字典之间的平等

假设字典键和值有正确实现的equals和hash方法,testing两个字典相等的最简洁和有效的方法是什么?

在这种情况下,如果两个字典包含相同的一组密钥(顺序不重要),则说它们是相等的,并且对于每个这样的密钥,它们都同意这个值。

这里有一些我想出来的方法(可能还有更多):

public bool Compare1<TKey, TValue>( Dictionary<TKey, TValue> dic1, Dictionary<TKey,TValue> dic2) { return dic1.OrderBy(x => x.Key). SequenceEqual(dic2.OrderBy(x => x.Key)); } public bool Compare2<TKey, TValue>( Dictionary<TKey, TValue> dic1, Dictionary<TKey, TValue> dic2) { return (dic1.Count == dic2.Count && dic1.Intersect(dic2).Count(). Equals(dic1.Count)); } public bool Compare3<TKey, TValue>( Dictionary<TKey, TValue> dic1, Dictionary<TKey, TValue> dic2) { return (dic1.Intersect(dic2).Count(). Equals(dic1.Union(dic2).Count())); } 
 dic1.Count == dic2.Count && !dic1.Except(dic2).Any(); 

这真的取决于你平等的意思。

此方法将testing两个字典包含具有相同值的相同键(假定这两个字典使用相同的IEqualityComparer<TKey>实现)。

 public bool CompareX<TKey, TValue>( Dictionary<TKey, TValue> dict1, Dictionary<TKey, TValue> dict2) { if (dict1 == dict2) return true; if ((dict1 == null) || (dict2 == null)) return false; if (dict1.Count != dict2.Count) return false; var valueComparer = EqualityComparer<TValue>.Default; foreach (var kvp in dict1) { TValue value2; if (!dict2.TryGetValue(kvp.Key, out value2)) return false; if (!valueComparer.Equals(kvp.Value, value2)) return false; } return true; } 

您可以使用linq进行键/值比较:

 public bool Compare<TKey, TValue>(Dictionary<TKey, TValue> dict1, Dictionary<TKey, TValue dict2) { IEqualityComparer<TValue> valueComparer = EqualityComparer<TValue>.Default; return dict1.Count == dict2.Count && dict1.Keys.All(key => dict2.ContainsKey(key) && valueComparer.Equals(dict1[key], dict2[key])); } 

@艾伦的回答 :

 bool equals = a.Intersect(b).Count() == a.Union(b).Count() 

是关于数组的,但就IEnumerable<T>方法而言,它也可以用于Dictionary<K,V>

我认为接受的答案是正确的,这是基于我在Exhel在smarthelp中读到的内容:“通过使用默认的相等比较器来比较值,生成两个序列的集合差异”。 但是我发现这不是一个好的答案。

考虑这个代码:

 Dictionary<string, List<string>> oldDict = new Dictionary<string, List<string>>() {{"001A", new List<string> {"John", "Doe"}}, {"002B", new List<string> {"Frank", "Abignale"}}, {"003C", new List<string> {"Doe", "Jane"}}}; Dictionary<string, List<string>> newDict = new Dictionary<string, List<string>>() {{"001A", new List<string> {"John", "Doe"}}, {"002B", new List<string> {"Frank", "Abignale"}}, {"003C", new List<string> {"Doe", "Jane"}}}; bool equal = oldDict.Count.Equals(newDict.Count) && !oldDict.Except(newDict).Any(); Console.WriteLine(string.Format("oldDict {0} newDict", equal?"equals":"does not equal")); equal = oldDict.SequenceEqual(newDict); Console.WriteLine(string.Format("oldDict {0} newDict", equal ? "equals" : "does not equal")); Console.WriteLine(string.Format("[{0}]", string.Join(", ", oldDict.Except(newDict).Select(k => string.Format("{0}=[{1}]", k.Key, string.Join(", ", k.Value)))))); 

这导致以下结果:

 oldDict does not equal newDict oldDict does not equal newDict [001A=[John, Doe], 002B=[Frank, Abignale], 003C=[Doe, Jane]] 

正如你所看到的,“oldDict”和“newDict”的设置完全一样。 build议的解决scheme和对SequenceEqual的调用都不能正常工作。 我不知道这是否是除了使用延迟加载或比较器设置为字典的方式的结果。 (虽然从结构和参考的解释看,它应该。)

这是我提出的解决scheme。 请注意,我使用的规则如下所示:如果两个字典都包含相同的密钥并且每个密钥的值匹配,则两个字典是相等的。 键和值都必须是相同的顺序。 而我的解决scheme可能不是最有效的,因为它依赖迭代整个键集。

 private static bool DictionaryEqual( Dictionary<string, List<string>> oldDict, Dictionary<string, List<string>> newDict) { // Simple check, are the counts the same? if (!oldDict.Count.Equals(newDict.Count)) return false; // Verify the keys if (!oldDict.Keys.SequenceEqual(newDict.Keys)) return false; // Verify the values for each key foreach (string key in oldDict.Keys) if (!oldDict[key].SequenceEqual(newDict[key])) return false; return true; } 

另外看看结果如何变化:按键顺序是不一样的。 (返回false)

 newDict = new Dictionary<string, List<string>>() {{"001A", new List<string> {"John", "Doe"}}, {"003C", new List<string> {"Doe", "Jane"}}, {"002B", new List<string> {"Frank", "Abignale"}}}; 

和键顺序匹配,但值不匹配(返回false)

 newDict = new Dictionary<string, List<string>>() {{"001A", new List<string> {"John", "Doe"}}, {"002B", new List<string> {"Frank", "Abignale"}}, {"003C", new List<string> {"Jane", "Doe"}}}; 

如果序列顺序无关紧要,则可以将该function更改为以下内容,但可能会导致性能下降。

 private static bool DictionaryEqual_NoSort( Dictionary<string, List<string>> oldDict, Dictionary<string, List<string>> newDict) { // Simple check, are the counts the same? if (!oldDict.Count.Equals(newDict.Count)) return false; // iterate through all the keys in oldDict and // verify whether the key exists in the newDict foreach(string key in oldDict.Keys) { if (newDict.Keys.Contains(key)) { // iterate through each value for the current key in oldDict and // verify whether or not it exists for the current key in the newDict foreach(string value in oldDict[key]) if (!newDict[key].Contains(value)) return false; } else { return false; } } return true; } 

检查如果DictionaryEqual_NoSort使用以下for newDict(DictionaryEquals_NoSort返回true):

 newDict = new Dictionary<string, List<string>>() {{"001A", new List<string> {"John", "Doe"}}, {"003C", new List<string> {"Jane", "Doe"}}, {"002B", new List<string> {"Frank", "Abignale"}}}; 

如果两个字典包含相同的密钥,但顺序不同,是否应该被认为是相同的? 如果不是的话,那么应该通过同时运用普查员来比较字典。 这可能比通过一个字典列举并查找其他元素中的每个元素要快。 如果你有先入为主的知识,平等的字典将有相同的顺序,他们的元素,这样的双重查点可能是要走的路。

在OP的问题中,它确实说过,平等testing不仅应该包括关键字的匹配,而且应该包括它们的价值。“ 在这种情况下,如果两个字典包含相同的一组关键字(顺序不重要) 每一个这样的关键,他们都认同这个价值 。“

我缺less的东西或标记的答案https://stackoverflow.com/a/3804852/916121只检查大小和密钥相等,但不是他们的价值?;

我会发布旁边的答案,但不能解决如何添加它作为评论,对不起。

对于嵌套字典和列表,我在这里结合了一些想法来做到这一点: https : //gist.github.com/NullVoxPopuli/f95baaa48b4e9854dcfe (太多的代码张贴在这里)〜100行