【问题标题】:Linq compare 2 object listsLinq比较2个对象列表
【发布时间】:2016-06-14 09:35:14
【问题描述】:

我知道类似的问题已经通过了这个委员会,但我找不到可以回答我的问题的问题。

我有 2 个list<myObject> 和 3 个属性。

班级:

    public int MeterID {get; set;}
    public string Datum { get; set; }
    public int NumberOfValues { get; set; }

    public myObject(int meterID, string datum, int numberOfValues)
    {
        this.ID= ID;
        this.Datum = datum;
        this.NumberOfValues = numberOfValues;
    }

我想根据以下 2 个值 ID, Datum 比较这些列表,但我希望结果仍然是 List<MyObject> 因此,当我的对象在 listA 和 listB 中时,它不应该在执行以下 linq 语句后出现在 newList

var newList = ListA.Select(x => new { x.ID, x.Datum }).Except(ListB.Select(z => new { z.ID, z.Datum }));

该语句没有为我提供一个 MyObject 列表,而是一个只有 ID 和数据的列表。我还需要 ListA 中的 NumberOfValues 属性位于 newList 中。

有没有办法用 linq 实现这一点?

【问题讨论】:

  • 为什么DatumString 而不是DateTime

标签: c# linq


【解决方案1】:

我会这样做:

var result = ListA.Where(a => 
                ListB.All(b => b.ID != a.ID || b.Datum != a.Datum)).ToList();

这会获取来自ListA 的所有元素,其中ListB 中的所有元素都不同(对于不同的定义)。

如果您还想拥有ListB 中不在ListA 中的元素,您可以合并结果:

var result = ListA.Where(a => 
                ListB.All(b => b.ID != a.ID || b.Datum != a.Datum)).
                Concat(ListB.Where(b => 
                        ListA.All(a => b.ID != a.ID || b.Datum != a.Datum)).
             ToList();

【讨论】:

  • 看起来这正是我想要的。
  • Curios:为什么你把点放在行尾而不是第二行? (例如: ListA.Where(x=>x>y).[newline]FirstOrDefault() 而不是 ListA.Wjere(x=>x>y)[newline].FirstOrDefault。我认为它比你的更清晰风格,声明继续
  • @Mafii 口味问题,我经常在格式化 SO 代码时遇到问题,尤其是长 linq“单行”。
【解决方案2】:

另一种选择是使用Enumerable.Except()IEqualityComparerlistB 中排除项目

public class MyObject
{
    public int MeterID { get; set; }
    public string Datum { get; set; }
    public int NumberOfValues { get; set; }

    public MyObject(int meterID, string datum, int numberOfValues)
    {
        this.MeterID = meterID;
        this.Datum = datum;
        this.NumberOfValues = numberOfValues;
    }
}

public class MyObjectEqualityComparer : EqualityComparer<MyObject>
{
    public override bool Equals(MyObject x, MyObject y)
    {
        return x.MeterID == y.MeterID
            && x.Datum == y.Datum;
    }

    public override int GetHashCode(MyObject obj)
    {
        return obj.MeterID ^ obj.Datum.GetHashCode();
    }
}

通过在外部对象中编码比较标准,可以更轻松地在其他地方重用它并简化更改。

[TestClass]
public class CompareListsFixture
{

    [TestMethod]
    public void CompareLists()
    {
        var listA = new List<MyObject>
        {
            new MyObject(1,"A", 5), // Matches with 1/A/1
            new MyObject(1,"B", 4),
            new MyObject(2,"A", 3), // Matches with 2/A/4
            new MyObject(2,"C", 2),
        };

        var listB = new List<MyObject>
        {
            new MyObject(1,"A", 1),
            new MyObject(2,"A", 4),
            new MyObject(3,"A", 8),
        };

        var expected = new List<MyObject>
        {
            new MyObject(1,"B", 4),
            new MyObject(2,"C", 2),
        };

        var actual = listA.Except(listB, new MyObjectEqualityComparer());

        CollectionAssert.AreEqual(expected, actual.ToList(), new MyObjectComparer());

    }

}

我们使用比较器来比较Collection.Assert()中的整个对象

public class MyObjectComparer : Comparer<MyObject>
{
    public override int Compare(MyObject x, MyObject y)
    {
        return Format(x).CompareTo(Format(y));
    }

    private static string Format(MyObject obj)
    {
        return $"{obj.MeterID}:{obj.Datum}:{obj.NumberOfValues}";
    }
}

【讨论】:

    猜你喜欢
    • 2022-06-26
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多