比较两个对象列表,并根据某些属性选择常见记录和差异记录

本文关键字:记录 属性 选择 常见 两个 对象 列表 比较 | 更新日期: 2023-09-27 18:29:19

如何基于属性Name将对象类型person的list A与person的list B进行比较,并获得另一个包含两个列表中共同的list C和位于list A但不位于list Blist D

比较两个对象列表,并根据某些属性选择常见记录和差异记录

var a = new List<int>();
var b = new List<int>();
var c = new List<int>();
var d = new List<int>();
c = a.Where(aItem => b.Any(bItem => aItem == bItem)).ToList();
d = a.Except(c).ToList();

你可以使用任何逻辑来比较一个项目和另一个项目。

以下是实现这一点的扩展方法。

public static class LinqEx
{
    public static bool DefaultCompare<T>(T one, T two)
    {
        return one.Equals(two);
    }
    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second)
    {
        return first.Common(second, DefaultCompare);
    }
    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, bool> compare)
    {
        return first.Where(i1 => second.Any(i2 => compare(i1, i2)));
    }
    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, out IEnumerable<T> difference)
    {
        return first.Common(second, out difference, DefaultCompare);
    }
    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, out IEnumerable<T> difference, Func<T, T, bool> compare)
    {
        var common = first.Common(second, compare);
        difference = first.Except(common);
        return common;
    }
    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, out List<T> difference)
    {
        IEnumerable<T> d;
        var common = first.Common(second, out d);
        difference = d.ToList();
        return common;
    }
    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, out List<T> difference, Func<T, T, bool> compare)
    {
        IEnumerable<T> d;
        var common = first.Common(second, out d, compare);
        difference = d.ToList();
        return common;
    }
}

用法:

List<myObjectType> d;
c = a.Common(b, out d, (i1, i2) => i1.Name == i2.Name).ToList();

我的答案与这里的其他答案相似,但在前半部分使用Intersect()方法,这是我认为最简单、最正确的方法,可以获得两个集合中存在的项目集:

 var a = new[] {new Person("Alice"), new Person("Bob")};
 var b = new[] {new Person("Bob"), new Person("Charlie")};
 var inBoth = a.Intersect(b, new PersonNameEqualityComparer());
 var notInB = a.Except(b, , new PersonNameEqualityComparer());

inBoth将包含Bob,而notInB将包含Alice。

这里唯一的问题是Intersect需要一个相等比较器,它可以获得两个Person对象,并根据它们的Name确定它们是否相等。我希望我们可以在这里指定一个lambda表达式,但在此之前,实现非常简单:

class PersonNameEqualityComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.Name == y.Name;
    }
    public int GetHashCode(Person obj)
    {
       return obj.Name.GetHashCode();
    }
}

简短的答案如下:

var c = listA.Join(listB, a => a.Name, b => b.Name, (a, b) => a).ToList();
var d = listA.Except(c).ToList();

这将根据每个对象的Name属性连接两个列表,并返回第一个列表中的公共对象。Except()方法将返回在listA bot中而不在c中的对象;使用CCD_ 16进行比较,如果将CCD_ 17更改为CCD_。为了避免这种情况,您必须实现IEqualityComparer<Person>并将其传递给方法Except(),如下所示:

var comparer = new PersonComparer(); // the class that implements IEqualityComparer<Person>
var d = listA.Except(c, comparer).ToList();