首页 > 解决方案 > LINQ Fluent 语法 - 取消选择数组中的项目

问题描述

我正在为 Fluent LINQ 查询而苦苦挣扎。我有一个Contributor带有Product数组的对象:

public class Product
{
    public int Id {get;set;}
    public string Role {get;set;}
    public string Publisher {get;set;}
}
public class Contributor
{
    public string Id {get;set;}
    public string Name {get;set;}
    public Product[] ProductsContributedTo {get;set;}
}

我有一个集合,Contributor我想过滤这些集合,以便:

  1. 我只选择数组Contributor中存在作者角色记录的记录。Contributor.ProductsContributedTo

  2. 每个贡献者Contributor.ProductsContributedTo数组应该只包含作者角色。

到目前为止,这是我的尝试:

 var authors = contributors.SelectMany(people => people.ProductsContributedTo
                                  .Where(product => product.Role == "Author")
                                  .Select(c => people))
                                  .ToList();

因此,这是可行的,我正在选择正确的贡献者记录,但是如何过滤Contributor.ProductsContributedTo以仅包含作者角色?

这是一个小提琴,证明我有 3 条贡献者记录Barry CollinsMaggie FenwickSedgewick Foley。上面的 LINQ 查询只正确选择了 Maggie Fenwick 和 Barry Collins,但是如何过滤Contributor.ProductsContributedTo数组以便我只有他们各自的 Author Product 记录?

https://dotnetfiddle.net/hScdi4

编辑:

我对 Fiddle 做了一点改动,因为每个都Contributor可以 Author multipleProduct所以我想澄清一下。

标签: c#linq

解决方案


它比你想象的要复杂得多:

List<Contributor> authors = contributors
    .Where(x => x.ProductsContributedTo.Any(y => y.Role == "Author"))
    .Select(x => new Contributor { Id = x.Id, Name = x.Name, ProductsContributedTo = x.ProductsContributedTo.Where(y => y.Role == "Author").ToArray() })
    .ToList();

您必须将其“克隆”ContributorContributor具有过滤ProductsContributedTo列表的新对象。

请注意,我过滤了两次Role == "Author",一次用于过滤Contributors,一次用于过滤ProductsContributedTo所选Contributors` 的。

其他方式,不重复检查Role是这样的:

List<Contributor> authors = contributors
    .Select(x => new { Contributor = x, FilteredProducts = x.ProductsContributedTo.Where(y => y.Role == "Author").ToArray() })
    .Where(x => x.FilteredProducts.Length != 0)
    .Select(x => new Contributor { Id = x.Contributor.Id, Name = x.Contributor.Name, ProductsContributedTo = x.FilteredProducts })
    .ToList();

我们将过滤后的“保存”在匿名对象中ProductsContributedTo,然后使用它FilteredProducts来过滤Contributors。这或多或少等同于将let关键字与基于关键字的 linq 一起使用:

List<Contributor> authors = (from x in contributors
                             let filteredProducts = x.ProductsContributedTo.Where(y => y.Role == "Author").ToArray()
                             where filteredProducts.Length != 0
                             select new Contributor { Id = x.Id, Name = x.Name, ProductsContributedTo = filteredProducts }
                            ).ToList();

Contributor请注意,通常您可以使用分别包含 the及其过滤的 s的匿名对象生活得很好Product,同时保持在sContributor的完整列表中Product

List<Contributor> authors = contributors
    .Select(x => new 
    { 
        Contributor = x, 
        FilteredProducts = x.ProductsContributedTo.Where(y => y.Role == "Author").ToArray() 
    })
    .Where(x => x.FilteredProducts.Length != 0)
    .ToList();

推荐阅读