在 C# 中比较两个字典的相等数据?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13470335/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing two dictionaries for equal data in c#?
提问by mezamorphic
I have two dictionaries containing a string key and then an object. The object contains five fields. Is there an elegant way to ensure both dictionaries first contain the same keys and then if this is correct, contain the same five fields per object?
我有两个字典,其中包含一个字符串键和一个对象。该对象包含五个字段。有没有一种优雅的方法来确保两个字典首先包含相同的键,然后如果这是正确的,每个对象包含相同的五个字段?
Would the two dictionaries have the same in-built hashcode or something?
这两个字典会具有相同的内置哈希码吗?
EDIT, doesn't appear to be working for the following code:
编辑,似乎不适用于以下代码:
Dictionary<string, MyClass> test1 = new Dictionary<string, MyClass>();
Dictionary<string, MyClass> test2 = new Dictionary<string, MyClass>();
MyClass i = new MyClass("", "", 1, 1, 1, 1);
MyClass j = new MyClass("", "", 1, 1, 1, 1);
test1.Add("1", i);
test2.Add("1", j);
bool equal = test1.OrderBy(r => r.Key).SequenceEqual(test2.OrderBy(r => r.Key));
class MyClass
{
private string a;
private string b;
private long? c;
private decimal d;
private decimal e;
private decimal f;
public MyClass(string aa, string bb, long? cc, decimal dd, decimal ee, decimal ff)
{
a= aa;
b= bb;
c= cc;
d= dd;
e= ee;
f= ff;
}
this returns false?
这返回假?
采纳答案by Habib
First you have to override Equalsand GetHashCodemethod in your class, otherwise comparison will be performed on references instead of actual values. (The code to override Equalsand GetHashCodeis provided at the end), after that you can use:
首先你必须在你的类中覆盖Equals和GetHashCode方法,否则将在引用而不是实际值上进行比较。(代码重写Equals,并GetHashCode在结束时提供),之后您可以使用:
var result = (dic1 == dic2) || //Reference comparison (if both points to same object)
(dic1.Count == dic2.Count && !dic1.Except(dic2).Any());
Since the order in which items in Dictionary are returned is undefined, you can not rely on Dictionary.SequenceEqual(without OrderBy).
由于返回 Dictionary 中项目的顺序未定义,因此您不能依赖Dictionary.SequenceEqual (没有OrderBy)。
You can try:
你可以试试:
Dictionary<string, object> dic1 = new Dictionary<string, object>();
Dictionary<string, object> dic2 = new Dictionary<string, object>();
dic1.Add("Key1", new { Name = "abc", Number = "123", Address = "def", Loc = "xyz" });
dic1.Add("Key2", new { Name = "DEF", Number = "123", Address = "def", Loc = "xyz" });
dic1.Add("Key3", new { Name = "GHI", Number = "123", Address = "def", Loc = "xyz" });
dic1.Add("Key4", new { Name = "JKL", Number = "123", Address = "def", Loc = "xyz" });
dic2.Add("Key1",new { Name = "abc",Number= "123", Address= "def", Loc="xyz"});
dic2.Add("Key2", new { Name = "DEF", Number = "123", Address = "def", Loc = "xyz" });
dic2.Add("Key3", new { Name = "GHI", Number = "123", Address = "def", Loc = "xyz" });
dic2.Add("Key4", new { Name = "JKL", Number = "123", Address = "def", Loc = "xyz" });
bool result = dic1.SequenceEqual(dic2); //Do not use that
Mostof the time the above will return true, but one can't really rely on that due to unordered nature of Dictionary.
大多数情况下,上述内容会返回true,但由于Dictionary.
Since SequenceEqualwill compare the order as well, therefore relying on onlySequenceEqualcould be wrong. You have to use OrderByto order both dictionaries and then use SequenceEquallike:
由于SequenceEqual将比较顺序为好,因此依靠唯一的SequenceEqual可能是错误的。您必须使用OrderBy对两个字典进行排序,然后使用SequenceEqual:
bool result2 = dic1.OrderBy(r=>r.Key).SequenceEqual(dic2.OrderBy(r=>r.Key));
But that will involve multiple iterations, once for ordering and the other for comparing each element using SequenceEqual.
但这将涉及多次迭代,一次用于排序,另一次用于使用SequenceEqual.
Code for overriding Equalsand GetHashCode
代码覆盖Equals和GetHashCode
private class MyClass
{
private string a;
private string b;
private long? c;
private decimal d;
private decimal e;
private decimal f;
public MyClass(string aa, string bb, long? cc, decimal dd, decimal ee, decimal ff)
{
a = aa;
b = bb;
c = cc;
d = dd;
e = ee;
f = ff;
}
protected bool Equals(MyClass other)
{
return string.Equals(a, other.a) && string.Equals(b, other.b) && c == other.c && e == other.e && d == other.d && f == other.f;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((MyClass)obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (a != null ? a.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (b != null ? b.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ c.GetHashCode();
hashCode = (hashCode * 397) ^ e.GetHashCode();
hashCode = (hashCode * 397) ^ d.GetHashCode();
hashCode = (hashCode * 397) ^ f.GetHashCode();
return hashCode;
}
}
}
You may also see: Correct way to override Equals() and GetHashCode()
回答by Rawling
You can use
您可以使用
bool dictionariesEqual =
dic1.Keys.Count == dic2.Keys.Count &&
dic1.Keys.All(k => dic2.ContainsKey(k) && object.Equals(dic2[k], dic1[k]));
回答by Philipp
In this case you can just use the SequenceEquals()-Method, like following:
在这种情况下,您可以只使用 SequenceEquals()-Method,如下所示:
Dictionary<string, object> d1 = new Dictionary<string, object>();
d1.Add("first", new { Name = "TestName", Age = 12, ID = 001 });
Dictionary<string, object> d2 = new Dictionary<string, object>();
d2.Add("first", new { Name = "TestName", Age = 12, ID = 001 });
Console.WriteLine(d1.SequenceEqual(d2)); //outputs True
Note: For simplicity i used implicit classes to fill the Dictionaries. The code will work the same way with any objects. The hashcodes of both dictionaries are not equal, which can be easily verified by doing the following:
注意:为简单起见,我使用隐式类来填充字典。该代码将与任何对象以相同的方式工作。两个字典的哈希码不相等,可以通过执行以下操作轻松验证:
Console.WriteLine(d1.GetHashCode() + " " + d2.GetHashCode()); //outputs different hashcodes
回答by Sebastian Negraszus
The built-in Equalsfunction of Dictionary<T>only checks for reference equality, see this question on SO. Hashcodes do not reliably tell you if two objects are equal; there is always a chance of hash collision. Never use hashcodes as an equality test!
仅检查引用相等性的内置Equals函数Dictionary<T>,请参阅SO 上的这个问题。哈希码不能可靠地告诉您两个对象是否相等;总是有散列冲突的机会。永远不要使用哈希码作为相等性测试!
I would do it by hand: Compare the entry count of both dictionaries, iterate over the key-value-pairs of one dictionary and check if the key exists in the other one and compare the corresponding objects from both dictionaries. Edit:See Rawling's answer :)
我会手工完成:比较两个字典的条目数,迭代一个字典的键值对并检查另一个字典中是否存在键,然后比较两个字典中的相应对象。编辑:见罗林的回答:)
回答by greyseal96
There were a couple of answers on here that I think got pretty close but there were a couple of additional points that I thought should be added so I'm adding them as another possible answer.
这里有几个我认为非常接近的答案,但我认为应该添加一些额外的要点,因此我将它们添加为另一个可能的答案。
First, I would avoid using the SequenceEquals method. It is an extension method for Enumerable and implicitly requires the two collections to be in the same order. Dictionaries are not meant to be ordered collections so using SequenceEquals means that you'll have to needlessly iterate over both of the dictionaries to create sorted/ordered intermediary collections that you also don't need and then iterate over those collections to compare them for equality. That seems really inefficient and an abuse of LINQ, all in the name of trying to be terse and write a one line solution. If the OP's idea of "elegant" is terse, I guess this will do the trick, but it seems wasteful.
首先,我会避免使用 SequenceEquals 方法。它是 Enumerable 的扩展方法,隐式要求两个集合的顺序相同。字典并不是有序集合,因此使用 SequenceEquals 意味着您必须不必要地遍历两个字典以创建您也不需要的已排序/有序的中间集合,然后遍历这些集合以比较它们的相等性. 这似乎非常低效,而且是对 LINQ 的滥用,所有这些都以试图简洁并编写一行解决方案的名义。如果 OP 的“优雅”的想法很简洁,我想这可以解决问题,但似乎很浪费。
On the other hand, if the OP's idea of "elegant" is efficient, then you'll probably need to write a little more code. First, you should either override the Equals method for your class or implement IEquatable in your class (see here, for example). This will allow you to compare the values in the dictionary. Then, you'll probably want to do something like implement an interface like IEqualityComparer for your dictionary.
另一方面,如果 OP 的“优雅”思想是有效的,那么您可能需要编写更多代码。首先,您应该为您的类覆盖 Equals 方法或在您的类中实现 IEquatable(例如,请参见此处)。这将允许您比较字典中的值。然后,您可能想要做一些事情,例如为您的字典实现一个类似 IEqualityComparer 的接口。
Then, the comparison of the two dictionaries would go something like below. It's just a quick and dirty "back of the napkin" example so it's not an example of the best way to do it, but it's meant to illustrate a way to iterate only as many times over the dictionary as necessary and quit out as soon as an inequality is found.
然后,两个字典的比较将如下所示。这只是一个快速而肮脏的“餐巾纸背面”示例,因此它不是最佳方法的示例,但它旨在说明一种方法,仅在必要时对字典进行多次迭代并尽快退出发现不等式。
First the required code:
首先需要的代码:
public class Foo
{
//members here...
public override bool Equals(object obj)
{
//implementation here
}
//You should probably also override GetHashCode to be thorough,
//but that's an implementation detail...
}
//This method could stand on its own or you could change it to make it
//part of the implementation of one of the comparison interfaces...
bool DictionariesEqual(Dictionary<string, Foo> x, Dictionary<string, Foo> y)
{
//If we're comparing the same object, it's obviously equal to itself.
if(x == y)
{
return true;
}
//Make sure that we don't have null objects because those are
//definitely not equal.
if (x == null || y == null)
{
return false;
}
//Stop processing if at any point the dictionaries aren't equal.
bool result = false;
//Make sure that the dictionaries have the same count.
result = x.Count == y.Count;
//If we passed that check, keep going.
if(result)
{
foreach(KeyValuePair<string, Foo> xKvp in x)
{
//If we don't have a key from one in the other, even though
//the counts are the same, the dictionaries aren't equal so
//we can fail out.
Foo yValue;
if(!y.TryGetValue(xKvp.Key, out yValue))
{
result = false;
break;
}
else
{
//Use the override of the Equals method for your object
//to see if the value from y is equal to the value from
//x.
result = xKvp.Value.Equals(yValue);
if(!result)
{
//If they're not equal we can just quit out.
break;
}
}
}
}
return result;
}
Then we'd use it like this:
然后我们会像这样使用它:
Dictionary<string, Foo> dict1 = new Dictionary<string, Foo>();
Dictionary<string, Foo> dict2 = new Dictionary<string, Foo>();
//Fill the dictionaries here...
//Compare the dictionaries
bool areDictsEqual = DictionariesEqual(dict1, dict2);
So, it's not the most terse code, but it's also not iterating more than necessary. In my opinion, that's more elegant.
所以,它不是最简洁的代码,但它也没有不必要的迭代。在我看来,这更优雅。

