我有两个使用ff的对象。类:
public class Test {
public string Name {get; set;}
public List<Input> Inputs {get;set;}
......
//some other properties I don't need to check
}
public class Input {
public int VariableA {get;set;}
public int VariableB {get;set;}
public List<Sancti> Sancts {get;set;}
}
public class Sancti {
public string Symbol {get;set;}
public double Percentage {get;set;}
}
我想检查Test
的两个实例是否具有相同的Inputs
值。我已经使用循环完成了这个,但我相信这不是这样做的方法。
我已经阅读了一些链接:link1,link2但它们对我来说似乎是胡言乱语。是否有更简单的方法可以做到这一点,比如:
test1.Inputs.IsTheSameAs(test2.Inputs)
?
我真的希望有一种更易读的方法。优先Linq
。
注意:输入顺序无关紧要。
答案 0 :(得分:2)
一种方法是检查两个列表之间的设置否定。如果listA
否定listB
的结果没有元素,则表示listA
中的所有内容都存在于listB
中。如果反之亦然,则两个列表相等。
bool equal = testA.Inputs.Except(testB.Inputs).Count() == 0
&& testB.Inputs.Except(testA.Inputs).Count() == 0;
另一个是简单地检查listA
的每个元素,看它是否存在于listB
中(反之亦然):
bool equal = testA.Inputs.All(x => testB.Inputs.Contains(x))
&& testB.Inputs.All(x => testA.Inputs.Contains(x));
这就是说,如果列表中的一个元素与另一个元素中的多个元素“相等”,则这些中的任何一个都会产生误报。例如,使用上述方法将以下两个列表视为相同:
listA = { 1, 2, 3, 4 };
listB = { 1, 1, 2, 2, 3, 3, 4, 4 };
为防止这种情况发生,您需要执行一对一搜索而不是核解决方案。有几种方法可以做到这一点,但一种方法是首先对两个列表进行排序,然后相互检查它们的索引:
var listASorted = testA.Inputs.OrderBy(x => x);
var listBSorted = testB.Inputs.OrderBy(x => x);
bool equal = testA.Inputs.Count == testB.Inputs.Count
&& listASorted.Zip(listBSorted, (x, y) => x == y).All(b => b);
(如果已经对列表进行了排序,或者您希望确切地检查列表(保留排序),那么您可以跳过此方法的排序步骤。)
然而,使用此方法需要注意的一点是,Input
需要实现IComparable
才能对它们进行适当的排序。您如何完全实现它取决于您,但一种可能的方法是根据Input
和VariableA
的XOR对VariableB
进行排序:
public class Input : IComparable<Input>
{
...
public int Compare(Input other)
{
int a = this.VariableA ^ this.VariableB;
int b = other.VariableA ^ other.VariableB;
return a.Compare(b);
}
}
(此外,Input
也应该覆盖GetHashCode
和Equals
,因为它的答案在其答案中描述了。)
修改强>
在回到这个答案之后,我现在想提供一个更简单的解决方案:
var listASorted = testA.Inputs.OrderBy(x => x);
var listBSorted = testB.Inputs.OrderBy(x => x);
bool equal = listASorted.SequenceEqual(listBSorted);
(如前所述,如果列表已经排序,或者您希望将它们与现有的排序完整比较,则可以跳过排序步骤。)
SequenceEqual
使用特定类型的相等比较器来确定相等性。默认情况下,这意味着检查两个对象之间所有公共属性的值是否相等。如果您想实施不同的方法,可以为IEqualityComparer
定义Input
:
public class InputComparer : IEqualityComparer<Input>
{
public bool Equals(Input a, Input b)
{
return a.variableA == b.variableA
&& a.variableB == b.variableB
&& ... and so on
}
public int GetHashCode(Input a)
{
return a.GetHashCode();
}
}
答案 1 :(得分:1)
您可以更改Input
和Sancti
类定义,以覆盖Equals
和GetHasCode
。以下解决方案在以下情况下认为2个输入相等:
VariableA
相等且VariableB
相等且Sancts
列表相同,考虑到具有相同Sancti
的{{1}}元素必须具有相同的Symbol
如果您的规格不同,您可能需要更改此信息:
Percentage
这样做,你只需要检查public class Input
{
public int VariableA { get; set; }
public int VariableB { get; set; }
public List<Sancti> Sancts { get; set; }
public override bool Equals(object obj)
{
Input otherInput = obj as Input;
if (ReferenceEquals(otherInput, null))
return false;
if ((this.VariableA == otherInput.VariableA) &&
(this.VariableB == otherInput.VariableB) &&
this.Sancts.OrderBy(x=>x.Symbol).SequenceEqual(otherInput.Sancts.OrderBy(x => x.Symbol)))
return true;
else
{
return false;
}
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + VariableA.GetHashCode();
hash = hash * 23 + VariableB.GetHashCode();
hash = hash * 23 + Sancts.GetHashCode();
return hash;
}
}
}
public class Sancti
{
public string Symbol { get; set; }
public double Percentage { get; set; }
public override bool Equals(object obj)
{
Sancti otherInput = obj as Sancti;
if (ReferenceEquals(otherInput, null))
return false;
if ((this.Symbol == otherInput.Symbol) && (this.Percentage == otherInput.Percentage) )
return true;
else
{
return false;
}
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + Symbol.GetHashCode();
hash = hash * 23 + Percentage.GetHashCode();
return hash;
}
}
}
是否相等:
Input