我在为一个流利的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集合,我希望过滤这些集合,以便:
Contributor数组中存在作者角色记录的情况下的Contributor.ProductsContributedTo记录。Contributor.ProductsContributedTo数组应该只包括作者角色。以下是我迄今为止的尝试:
var authors = contributors.SelectMany(people => people.ProductsContributedTo
.Where(product => product.Role == "Author")
.Select(c => people))
.ToList();因此,通过选择正确的贡献者记录,这是可行的,但是如何过滤Contributor.ProductsContributedTo,使其只包含作者角色?
这是一个小提琴,证明我有3名贡献者记录巴里柯林斯,玛吉芬威克和塞奇威克福利。上面的LINQ查询只正确地选择了麦琪·芬威克和巴里·柯林斯,但是我如何过滤Contributor.ProductsContributedTo数组,使我只拥有他们各自的作者产品记录?
https://dotnetfiddle.net/hScdi4
编辑:
我对Fiddle做了一点小小的修改,因为每个Contributor都可以编写多个Product,所以我想说明这一点。
发布于 2018-06-28 10:45:33
这比你想象的要复杂得多:
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“克隆”到具有筛选的ProductsContributedTo列表的新Contributor中。
请注意,我为Role == "Author"过滤了两次,一次用于过滤Contributors,一次用于过滤所选Contributors的ProductsContributedTo。
另一种方法是,无需重复检查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。这或多或少相当于在基于关键字的linq中使用let关键字:
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的匿名对象,同时在Contributor中保留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();发布于 2018-06-28 10:42:58
下面的代码应该可以工作,它首先选择贡献者及其作者角色产品,然后只保留那些至少有一个产品的贡献者(以避免多次迭代产品集合):
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));发布于 2018-06-28 10:53:03
试着跟着。其他解决方案没有使用SelectMany。使用just添加一个额外的层,这是不必要的。:
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();https://stackoverflow.com/questions/51080652
复制相似问题