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

时间:2014-05-23 15:25:24

标签: c# linq

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

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次。

通过在一个易于阅读的Linq操作中计算所有4个值,我有什么方法可以充分利用这两个世界?

3 个答案:

答案 0 :(得分:1)

请注意,没有(实际)优化可以让它更快。您将需要Θ(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;

我没有看到别的东西。

答案 1 :(得分:0)

正如Shoe正确指出的那样,如果你的比较和差异是完全独立的,据我所知,除了foreach声明(你的第一个解决方案)之外,没有办法以更高效和简洁的方式做到这一点。但是,使用Any代替All

可以改善您的Linq解决方案
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解决方案表现更差。

答案 2 :(得分:-2)

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

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不必加密以使冲突不可能。此域中的冲突非常不可能,但当然不是不可能的。否则,您始终可以使用加密哈希函数来保证安全。 当每个值的重新分配运行值时,也会覆盖字符串的顺序。

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

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