根据一些共同的列和 return 个不匹配的项目比较两个不同的通用列表

Compare two different generic lists based on some common columns and return unmatched items

我有 2 个不同的通用列表,其中包含一些我想用于比较的公共字段和 return 来自其他列表的不匹配行,反之亦然。

第一个列表:列出 freightCharges 第二个列表:列出 shippingCharges

我想比较这两个列表,其中“家庭”在第二个列表中不匹配,并生成一个新的差异列表,我想在下一步中反之亦然,但以下查询不是 return在有差异的情况下进行任何操作:

var list0 = shippingCharges.Where(item => freightCharges.All(f => item.Buid == f.BUID && item.Catalog == (f.Catalog != null ? f.Catalog : null)
                            && item.Productline == (f.ProductLine != null ? f.ProductLine : null)
                            && item.Brand == (f.Brand != null ? f.Brand : null) && item.Family != (f.Family != null ? f.Family : null))).ToList();

There was some possibility of null so, I handled them as well.

我想将一个列表的每个列表项与另一个进行比较。我可以使用 foreach 循环,但我认为在 Linq 中会有同样的东西可用。

您必须重写所比较模型的 Equal 方法。请参阅 MSDocs 中的 link,了解有关如何以及为何这样做的更多信息。

https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=net-6.0

我们以两个类为例:

public class ShippingCharges
{
    public string ProductLine { get; set; }
    public int Family { get; set; }
}

public class FreightCharges
{
    public string Brand { get; set; }
    public int? Family { get; set; }
}

我们添加一些值:

var ListA = new List<ShippingCharges>() {
    new ShippingCharges()
    {
        ProductLine = "1",
        Family = 1
    },
    new ShippingCharges()
    {
        ProductLine = "1",
        Family = 2
    },
};

var ListB = new List<FreightCharges>(){
    new FreightCharges()
    {
        Brand = "2",
        Family = 2
    },
    new FreightCharges()
    {
        Brand = "3",
        Family = 3
    },
};

添加一些 LINQ 扩展:

public static class LinqExtensions
{
    public static IEnumerable<TSource> Except<TSource, VSource>(this IEnumerable<TSource> first, IEnumerable<VSource> second, Func<TSource, VSource, bool> comparer)
    {
        return first.Where(x => second.Count(y => comparer(x, y)) == 0);
    }

    public static IEnumerable<TSource> Contains<TSource, VSource>(this IEnumerable<TSource> first, IEnumerable<VSource> second, Func<TSource, VSource, bool> comparer)
    {
        return first.Where(x => second.FirstOrDefault(y => comparer(x, y)) != null);
    }

    public static IEnumerable<TSource> Intersect<TSource, VSource>(this IEnumerable<TSource> first, IEnumerable<VSource> second, Func<TSource, VSource, bool> comparer)
    {
        return first.Where(x => second.Count(y => comparer(x, y)) == 1);
    }
}

获取列表 A 中不在列表 b 中的所有元素:

var newData = ListA.Except(ListB, (a,b) => a.Family == b.Family);

备注:f.Brand != null ? f.Brand : null等于f.Brand ?? null等于f.Brand

如果您将更频繁地使用它来处理不同的 类,我的建议是为此创建一个通用扩展方法,这样您就可以像标准 LINQ 方法一样重用它。如果您不熟悉扩展方法,请阅读 Extension Methods Demystified

所以我们必须输入不同类型的序列。序列 1 中的对象具有 属性 X,序列中的对象具有 属性 Y。您可以检查属性 X 和 Y 的值是否相等。

要求:return 序列 1 中的所有对象,其 属性 X 的值不等于序列 2 中对象的任何 Y 值。将此与副连接-相反。

所以我们先为一侧做一个程序。然后我们用 Concat 重用它,反之亦然

public static WhereNotMatched<Touter, Tinner, TKey>(
    this IEnumerable<Touter> outer,
    IEnumerable<Tinner> inner,
    Func<Touter,TKey> outerKeySelector,
    Func<TInner,TKey> innerKeySelector)
{
    return WhereNotMatched(outer, inner, outerKeySelector, innerKeySelector, null);
{

public static IEnumerable<Touter> WhereNotMatched<Touter, Tinner, TKey>(
    this IEnumerable<Touter> outer,
    IEnumerable<Tinner> inner,
    Func<Touter,TKey> outerKeySelector,
    Func<TInner,TKey> innerKeySelector  
    IEqualityComparer<TKey> comparer)
{
    // if no comparer provided, use the default comparer
    if (comparer == null) comparer = EqualityComparer<TKey>.Default;

    // TODO: check outer != null, inner != null, etc.

    // extract all inner keys, for efficient lookup put them in a HashSet<TKey>
    HashSet<TKey> innerKeys = new HashSet(inner.Select(i => innerKeySelector(i)), comparer);

    // return all outer that have no corresponding value in the HashSet
    return outer.Where(o => !innerKeys.Contains(innerKeySelector(o));
}

用法:

假设在一个订购系统中您有 Products、Orders 和 OrderLines。每个 OrderLine 都有一个外键 ProductId。此 ProductId 指的是此 OrderLine 中提到的产品。每个订单包含零个或多个订单行。

IEnumerable<Order> orders = ...
IEnumerable<Product> products = ...

// Get all Products that have never been ordered yet
IEnumerable<OrderLine> orderLines = orders.SelectMany(order => order.OrderLines);

IEnumerable<Product> neverOrderedProducts = products.WhereNotMatched(orderLines,
    product => product.Id,
    orderLine => orderLine.ProductId);

以下是您要的更多内容:

IEnumerable<Student> maleStudents = ...
IEnumerable<Student> femaleStudents = ...

假设每个学生都有 PromCompanion。我们不是老式的,所以一些男性学生有一个不是女性学生的 PromCompanion,同样,一些女性学生有一个非男性学生作为 PromCompanion。找到所有这些学生。

IEnumerable<Student> result = maleStudents.WhereNotMatched(femaleStudents,
    man => man.PromCompanion,
    woman => woman.PromCompanion)
// concat with vice-versa
.Concat(femaleStudents.WhereNotMatched(maleStudents,
    woman => woman.PromCompanion,
    man => man.PromCompanion));



IEnumreable<Student> uncompaniedStudents = maleStudents.WhereNon