使用 lambda 和 LINQ 在 C# 中测试两个范围内的元素是否相等

Test whether the elements in two ranges are equal in C# using a lambda and LINQ

是否有 LINQ 或 C# 方法可以帮助在 C# 中使用 lambda 和 LINQ 测试两个范围内的元素是否相等。

事实上,我有 2 个对象数组,我想检查两个数组对象上的 属性 是否相同。

在 C++ 中,有 std::equal 可以与 lambda 一起使用(示例灵感来自 https://www.cplusplus.com/reference/algorithm/equal/

// equal algorithm example
#include <iostream>     // std::cout
#include <algorithm>    // std::equal
#include <vector>       // std::vector

bool mypredicate (int i, int j) {
  return (i==j);
}

int main () {
  int myints[] = {20,40,60,80,100};               //   myints: 20 40 60 80 100
  std::vector<int>myvector (myints,myints+5);     // myvector: 20 40 60 80 100

  myvector[3]=81;                                 // myvector: 20 40 60 81 100

  // using predicate comparison:
  if ( std::equal (myvector.begin(), myvector.end(), myints, [](int i, int j){ return i % 2 == 0 && j % 2 == 0; }) )
    std::cout << "The contents of both sequences are equal.\n";
  else
    std::cout << "The contents of both sequences differ.\n";

  return 0;
}

更新:另一个与我正在尝试做的很接近的 C++ 示例:

#include <algorithm>    // std::equal
#include <iostream>     // std::cout
#include <string>     // std::string
#include <vector>       // std::vector

using namespace std;

struct Device
{
    Device(string id) : id(id) {}
    string id;
};

int main () {
  Device mydevices[] = {Device("A1"), Device("A2")};
  std::vector<Device> myvector(mydevices,mydevices+2);

  mydevices[1].id = "B1";

  // using predicate comparison:
  if ( std::equal (myvector.begin(), myvector.end(), mydevices, [](Device i, Device j){ return i.id == j.id; }) )
    std::cout << "The contents of both sequences are equal.\n";
  else
    std::cout << "The contents of both sequences differ.\n";

  return 0;
}

您可以使用 Zip to create an IEnumerable of tuples. With All 您可以检查是否所有这些元组都满足条件:

Device[] devices1 = {new Device("A1"), new Device("A2")};
Device[] devices2 = {new Device("A1"), new Device("A2")};

if(devices1.Zip(devices2).All(x => x.Item1.ID == x.Item2.ID))
{
    Console.WriteLine("devices1 and devices2 IDs are the same");
}

在线演示:https://dotnetfiddle.net/FIFOYP

您可以使用 SequenceEqual:

int[] myints = {20,40,60,20,40};
IEnumerable<int> range1 = myints.Take(2);
IEnumerable<int> range2 = myints.Skip(3);
bool equalRanges = range1.SequenceEqual(range2); // true

如果您需要比较对象属性,您有多种选择:

  1. 覆盖EqualsGetHashCode并使用上面的代码

  2. 实现IEquatable<YourObjectType>并使用上面的代码

  3. 实现自定义 IEqualityComparer<YourObjectType> 并将其实例用作 SequenceEqual 和上述代码

    的参数
  4. 像这样使用不同的 LINQ 查询:

    YourObjectType[] myobjects = {...};
    IEnumerable<YourObjectType> range1 = myobjects.Take(2);
    IEnumerable<YourObjectType> range2 = myobjects.Skip(3);
    bool equalRanges = range1.Zip(range2, (x1, x2) => AreEqual(x1, x2)).All(b => b);
    

(其中 AreEqual 是一种比较属性的方法,您也可以内联执行此操作)

解决您编辑过的问题:

您似乎有一个类型的数组,其中包含您要比较的 属性,忽略其他属性。

此外,您要比较的 属性 的类型实现了 IEquals<T>GetHashCode()(因为它是 string)。

在这种情况下,您可以像这样比较两个数组:

using System;
using System.Linq;

static class Program
{
    public static void Main()
    {
        TestClass[] a1 = { new ("1", 1), new ("2", 2), new ("3", 3) };
        TestClass[] a2 = { new ("1", 2), new ("2", 3), new ("3", 4) };

        bool propertiesAreEqual = 
            a1.Select(element => element.PropertyToCompare)
            .SequenceEqual(
                a2.Select(element => element.PropertyToCompare));

        Console.WriteLine(propertiesAreEqual); // True
    }
}

record TestClass(string PropertyToCompare, int SomeOtherProperty);

在 DotNetFiddle 中试试:https://dotnetfiddle.net/NR6bog

注意:为了简洁起见,我使用 record。当然,这也适用于正常的 class。