检查对象列表中多个值的一致性的最干净的方法

本文关键字:一致性 方法 列表 对象 检查 | 更新日期: 2023-09-27 18:04:44

我想确定一个集合中对象的几个值是否都相同。我想到了两种主要的方法;但两者都不完全令人满意。在这两种情况下,我通过将每个对象的值与集合中第一个对象的值进行比较来进行检查。第一种方法是迭代集合,同时检查每个值:

bool string1Varies = false;
bool string2Varies = false;
bool string3Varies = false;
bool string4Varies = false;

foreach (Foo foo in myFooList)
{
    if (foo.string1 != myFooList[0].string1)
        string1Varies = true;
    if (foo.string2 != myFooList[0].string2)
        string2Varies = true;
    if (foo.string3 != myFooList[0].string3)
        string3Varies = true;
    if (foo.string4 != myFooList[0].string4)
        string4Varies = true;
    //optionally break if all 4 bools are true
}

如果正常情况下所有值都相同,这种方法的优点是只迭代一次集合,但有点冗长。如果所有4种变化都是常见的,我就可以通过添加一个检查来打破循环来提高它的性能;但是这会给迭代增加更多的开销,使它变得更长。

或者我可以使用Linq:

单独计算每个bool值
bool string1Varies = myFooList.All(foo => foo.string1 = myFooList[0].string1);
bool string2Varies = myFooList.All(foo => foo.string2 = myFooList[0].string2);
bool string3Varies = myFooList.All(foo => foo.string3 = myFooList[0].string3);
bool string4Varies = myFooList.All(foo => foo.string4 = myFooList[0].string4);

这样做的优点是简洁,如果更改发生在集合的早期,则会快速失败,但如果值相同,则会迭代整个集合4次。

是否有任何方法,我可以得到两全其美的计算所有4个值在一个单一的易于阅读的Linq操作?

检查对象列表中多个值的一致性的最干净的方法

请注意,没有(实际的)优化可以使此更快。您将需要Θ(n)循环迭代(带有一些假设)来执行此检查。

您的条件彼此之间没有依赖关系,因此它们必须保持独立。您可以进行的冗长更改包括重写第一个解决方案中的条件。

string1Varies |= foo.string1 != myFooList[0].string1;
string2Varies |= foo.string2 != myFooList[0].string2;
string3Varies |= foo.string3 != myFooList[0].string3;
string4Varies |= foo.string4 != myFooList[0].string4;

我没看到其他的

正如Shoe正确指出的那样,如果你的比较和差异是完全独立的,据我所知,没有比foreach语句(你的第一个解决方案)更高效和简洁的方法了。但是,您的Linq解决方案可以通过使用Any而不是All来改进:

bool string1Varies = myFooList.Any(foo => foo.string1 != myFooList[0].string1);
bool string2Varies = myFooList.Any(foo => foo.string2 != myFooList[0].string2);
bool string3Varies = myFooList.Any(foo => foo.string3 != myFooList[0].string3);
bool string4Varies = myFooList.Any(foo => foo.string4 != myFooList[0].string4);

这样,如果其中一个值不同,您就不会迭代整个集合。但请注意,由于多次迭代,它的性能仍然比foreach解决方案差。

用于比较对象内属性的任何差异:

IEnumerable<long> hashed = myList.Select(
    (item) => new string[] { item.String1, item.String2, item.String3, item.String4 }
    .Aggregate<string, long>(0, (runningHash, actual) => 
        (runningHash + actual.GetHashCode()) * 2654435761 % (int)Math.Pow(2, 32)));
bool areAllSame = hashed.Skip(1)
    .FirstOrDefault((item) => item != hashed.First()) == null;

它的作用:在所有属性上创建一个运行的哈希函数(使用knuth哈希算法)。GetHashCode不一定要加密才能避免碰撞。这个域中的碰撞非常不可能,但当然不是不可能。否则,为了安全起见,您总是可以使用加密散列函数。字符串的顺序也包括在运行值为每个值重新散列时。

不要抱怨细节,把它作为另一种方法。-->对所有属性进行一次哈希,使相等可以在一个循环中直接比较。

在最坏的情况下这是O(n*m)…(m =属性数)