C# 优化复杂对象比较
我有一个模型类C# 优化复杂对象比较,c#,list,performance,linq,comparison,C#,List,Performance,Linq,Comparison,我有一个模型类Class1,我想比较Class1的两个实例是否相同(结构相等) 公共类类别1:IEquatable { 公共字符串Id{get;set;} 公共字符串名称{get;set;} 公共IList类2s{get;set;} 公共布尔等于(1类其他) { 返回QuestName.Equals(其他.QuestName) &&Class2s.OrderBy(c=>c.Id).SequenceEqual(其他.Class2s.OrderBy(c=>c.Id)); //下面的方法很快,但不太准
Class1
,我想比较Class1
的两个实例是否相同(结构相等)
公共类类别1:IEquatable
{
公共字符串Id{get;set;}
公共字符串名称{get;set;}
公共IList类2s{get;set;}
公共布尔等于(1类其他)
{
返回QuestName.Equals(其他.QuestName)
&&Class2s.OrderBy(c=>c.Id).SequenceEqual(其他.Class2s.OrderBy(c=>c.Id));
//下面的方法很快,但不太准确
//因为具有相同哈希代码的两个对象可能相等,也可能不相等
//返回GetHashCode()==other.GetHashCode();
}
公共覆盖布尔等于(对象对象对象)
{
返回obj为Class1
&&等于(obj为1类);
}
公共覆盖int GetHashCode()
{
未经检查
{
int hash=13;
hash=(hash*7)+Name.GetHashCode();
foreach(Class2s.OrderBy中的var c2(c=>c.Id))
{
hash=(hash*7)+c2.GetHashCode();
}
返回散列;
}
}
}
公共类类别2:IEquatable
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共IList类3s{get;set;}
公共布尔等于(第2类其他)
{
返回Id==other.Id
&&Name.Equals(其他.Name)
&&Class3s.OrderBy(c=>c.Id).SequenceEqual(other.Class3s.OrderBy(c=>c.Id));
}
公共覆盖布尔等于(对象对象对象)
{
返回obj为Class2
&&这等于(obj为第2类);
}
公共覆盖int GetHashCode()
{
未经检查
{
int hash=13;
hash=(hash*7)+Id.GetHashCode();
hash=(hash*7)+Name.GetHashCode();
foreach(Class3s.OrderBy(c=>c.Id)中的变量c3)
{
hash=(hash*7)+c3.GetHashCode();
}
返回散列;
}
}
}
公共类类别3:IEquatable
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共IList类4s{get;set;}
公共布尔等于(第3类其他)
{
返回Id==other.Id
&&Name.Equals(其他.Name)
&&Class4s.OrderBy(c=>c.Id).SequenceEqual(other.Class4s.OrderBy(c=>c.Id));
}
公共覆盖布尔等于(对象对象对象)
{
返回obj为Class3
&&这等于(obj作为第3类);
}
公共覆盖int GetHashCode()
{
未经检查
{
int hash=13;
hash=(hash*7)+Id.GetHashCode();
hash=(hash*7)+Name.GetHashCode();
foreach(Class4s.OrderBy中的var c(c=>c.Id))
{
hash=(hash*7)+c.GetHashCode();
}
返回散列;
}
}
}
公共类类别4:IEquatable
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共布尔等于(第4类其他)
{
返回Id.Equals(其他.Id)
&&Name.Equals(其他名称);
}
公共覆盖布尔等于(对象对象对象)
{
返回obj为Class4
&&这等于(obj为第4类);
}
公共覆盖int GetHashCode()
{
未经检查
{
int hash=13;
hash=(hash*7)+Id.GetHashCode();
hash=(hash*7)+Name.GetHashCode();
返回散列;
}
}
}
我说当:1.它们具有相同的
名称
2.它们具有相同的
Class2
对象(它们的顺序无关紧要)
两个Class2
对象相等:1.它们具有相同的Id
2.他们有相同的名字
3.它们具有相同的
Class3
对象(它们的顺序无关紧要)
两个Class3
对象相等:1.它们具有相同的Id
2.他们有相同的名字
3.它们具有相同的
Class4
对象(它们的顺序无关紧要)
两个Class4
对象相等:1.它们具有相同的Id
2.他们有相同的名字 我使用
Equals
方法对它们进行比较,并像这样测量运行时间:
Class1 obj1 = GetFirstClass1Object();
Class1 obj2 = GetSecondClass1Object();
var startTime = DateTime.Now;
bool equals = obj1.Equals(obj2);
var elaspedTime = DateTime.Now.Substract(startTime)
上述解决方案工作正常,但速度非常慢。
我知道如果我们展平obj1
和obj2
,它们每个都包含3500个Class4
对象,比较obj1
和obj2
大约需要12秒
有没有更快的办法?我能不能利用散列来加快速度
另外,
obj1
和obj2
中的Class2
、Class3
和Class4
对象的数量总是相同的对列表进行排序以进行比较对我来说似乎效率很低。您可以尝试使用其他方法来比较列表
而不是
Class2s.OrderBy(c => c.Id).SequenceEqual(other.Class2s.OrderBy(c => c.Id)
你可以试试类似的东西
!Class2s.Except(other.Class2s).Any()
如果大多数对象不相等,还可以添加额外的测试,以确保列表在大小不相同时不会循环:
Class2s.Count == other.Class2s.Count && !Class2s.Except(other.Class2s).Any()
当然,您也可以对Class2.Equals()和Class3.Equals方法执行同样的操作 以提供的类为例,考虑以下结构。没有基于您的示例的示例数据可供测试,因此您必须使用现有的数据进行测试
public class Class1 : IEquatable<Class1> {
public int Id { get; set; }
public string Name { get; set; }
public IList<Class2> Class2s { get; set; }
public static bool operator ==(Class1 left, Class1 right) {
return Equals(left, right);
}
public static bool operator !=(Class1 left, Class1 right) {
return !(left == right);
}
public bool Equals(Class1 other) {
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(this.ToString(), other.ToString());
}
public override bool Equals(object obj) {
return obj is Class1 other && this.Equals(other);
}
public override int GetHashCode() {
return ToString().GetHashCode();
}
public override string ToString() {
var cs = Class2s == null ? "" : string.Join("", Class2s.OrderBy(_ => _.Id).Select(_ => _.ToString()));
return string.Join("", Id, Name, cs);
}
}
public class Class2 : IEquatable<Class2> {
public int Id { get; set; }
public string Name { get; set; }
public IList<Class3> Class3s { get; set; }
public static bool operator ==(Class2 left, Class2 right) {
return Equals(left, right);
}
public static bool operator !=(Class2 left, Class2 right) {
return !(left == right);
}
public bool Equals(Class2 other) {
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(this.ToString(), other.ToString());
}
public override bool Equals(object obj) {
return obj is Class2 other && this.Equals(other);
}
public override int GetHashCode() {
return ToString().GetHashCode();
}
public override string ToString() {
var cs = Class3s == null ? "" : string.Join("", Class3s.OrderBy(_ => _.Id).Select(_ => _.ToString()));
return string.Join("", Id, Name, cs);
}
}
public class Class3 : IEquatable<Class3> {
public int Id { get; set; }
public string Name { get; set; }
public IList<Class4> Class4s { get; set; }
public static bool operator ==(Class3 left, Class3 right) {
return Equals(left, right);
}
public static bool operator !=(Class3 left, Class3 right) {
return !(left == right);
}
public bool Equals(Class3 other) {
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(this.ToString(), other.ToString());
}
public override bool Equals(object obj) {
return obj is Class3 other && this.Equals(other);
}
public override int GetHashCode() {
return ToString().GetHashCode();
}
public override string ToString() {
var cs = Class4s == null ? "" : string.Join("", Class4s.OrderBy(_ => _.Id).Select(_ => _.ToString()));
return string.Join("", Id, Name, cs);
}
}
public class Class4 : IEquatable<Class4> {
public int Id { get; set; }
public string Name { get; set; }
public static bool operator ==(Class4 left, Class4 right) {
return Equals(left, right);
}
public static bool operator !=(Class4 left, Class4 right) {
return !(left == right);
}
public bool Equals(Class4 other) {
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(this.ToString(), other.ToString());
}
public override bool Equals(object obj) {
return obj is Class4 other && Equals(other);
}
public override int GetHashCode() {
return ToString().GetHashCode();
}
public override string ToString() {
return string.Format("{0}{1}", Id, Name);
}
}
公共类类别1:IEquatable{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共IList类2s{get;set;}
公共静态布尔运算符==(左1类,右1类){
返回等于(左、右);
}
公共静态布尔运算符!=(左1类,右1类){
返回!(左==右);
}
公共布尔等于(1类其他){
if(ReferenceEquals(null,other))返回false;
如果(ReferenceEquals(this,other))retu
| Method | Mean | Error | Ratio |
|----------------------------------------------------------------------- |------------:|------:|------:|
| 'Original code' | 535.46 ms | NA | 1.00 |
| 'Custom dictionary-based SequenceEquals' | 6,606.23 ms | NA | 12.34 |
| 'Custom dictionary-based SequenceEquals, classes cache their HashCode' | 1,136.91 ms | NA | 2.12 |
| 'Custom Except()-based SequenceEquals' | 2,281.12 ms | NA | 4.26 |
| 'Custom Except()-based SequenceEquals, classes cache their HashCode' | 257.46 ms | NA | 0.48 |
| 'No OrderBy()' | 76.31 ms | NA | 0.14 |