我正在努力使用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;}
}
的集合,我想过滤这些集合,以便:
我只选择Contributor
数组中存在作者角色记录的Contributor
条记录。
每个贡献者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
,所以我想弄清楚这一点。
答案 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")));
然后处理您的变量。
希望有帮助。