LINQ Fluent语法-取消选择数组中的项目

时间:2018-06-28 10:31:40

标签: c# linq

我正在努力使用Fluent LINQ查询。我有一个JSONObject数组的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;} } 的集合,我想过滤这些集合,以便:

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

  2. 每个贡献者Contributor.ProductsContributedTo数组应仅包括作者角色。

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

Contributor.ProductsContributedTo

因此可以通过这种方式来选择正确的参与者记录,但是如何过滤 var authors = contributors.SelectMany(people => people.ProductsContributedTo .Where(product => product.Role == "Author") .Select(c => people)) .ToList(); 以仅包括作者角色?

这里有个小提琴,表明我有3个贡献者记录,包括 Barry Collins Maggie Fenwick Sedgewick Foley 。上面的LINQ查询正确地仅选择了Maggie Fenwick和Barry Collins,但是如何过滤Contributor.ProductsContributedTo数组,这样我才只有各自的Author Product记录?

https://dotnetfiddle.net/hScdi4

编辑:

我对小提琴做了些微更改,因为每个Contributor.ProductsContributedTo可以创作多个Contributor,所以我想弄清楚这一点。

4 个答案:

答案 0 :(得分:2)

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

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();

您必须将Contributor“克隆”到具有过滤后的Contributor列表的新ProductsContributedTo

请注意,我为Role == "Author"过滤了两次,一次过滤了Contributor,一次过滤了所选ProductsContributedTo中的Contributor。< / p>

以其他方式,而无需重复对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来过滤Contributor。这或多或少等同于将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及其过滤后的Product的匿名对象一起生活,同时将{{1}的完整列表保留在Contributor中} s:

Product

答案 1 :(得分:0)

以下代码应该起作用,它首先选择具有作者角色产品的贡献者,然后仅保留具有至少一个产品的贡献者(以避免多次遍历产品集合):

contributors.Select(contributor => 
    new Contributor()
    {
        Id = contributor.Id,
        Name = contributor.Name,
        ProductsContributedTo = contributor.ProductsContributedTo.Where(
            product => (product.Role == "Author")).ToArray()
    }).
    Where(contributor => (contributor.ProductsContributedTo.Length > 0));

答案 2 :(得分:0)

尝试以下。其他解决方案不使用SelectMany。仅使用Select即可添加不必要的额外图层。 :

            var authors = contributors.SelectMany(people => people.ProductsContributedTo
                                 .Where(product => product.Role == "Author").Select(product => new { Id = product.Id, publisher = product.Publisher })
                                 .Select(c => new { contributorId = people.Id, name = people.Name, productId = c.Id, publisher = c.publisher }))
                                 .ToList();

答案 3 :(得分:0)

将贡献者选择为变量后,您可以删除除“作者:”以外具有其他角色的产品。

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

authors.ForEach(people => people.ProductsContributedTo.RemoveAll(item => item.Role != "Author")));

然后处理您的变量。

希望有帮助。