C# Linq - 从每个组中选择前2个

3
我需要为每个ProductTypeName获取前2个产品:
var productDetails = (from p in products
                            join po in productOrganisations 
                            on p.Id equals po.ProductId
                            where po.OrganisationId == id
                            where p.ProductTypeId == (typeId > 0 ? typeId : p.ProductTypeId) //filter by type if specified
                            where p.IsLive
                            select new
                            {
                                Id = p.Id,
                                Name = p.Name,
                                SupplierName = p.Supplier.Name,
                                ProductTypeName = p.ProductType.Name,
                                ShortDescription = p.ShortDescription,
                                ProductTypeId = p.ProductTypeId,
                                DatePublished = p.DatePublished,
                                CurrencyId = p.CurrencyId,

                            })
                            .AsNoTracking()
                            .ToArray();

目前以上语句返回所有产品,数以百计。每个产品都有一个属性ProductTypeName。
我需要按照ProductTypeName进行分组,然后按照datepublished降序获取每组中的前两个产品。
有什么想法吗?

1
使用 take 函数。 - johnny 5
2个回答

6

这里有一个很好的解答提供者是ChrisWue。如果他的回答解决了你的问题,请给他点个赞。

首先对列表进行强类型处理,然后使用GroupByOrderByTake来获取结果。

将结果集也进行强类型处理:

List<ProductDetails> myProductList = (from p in products
                        join po in productOrganisations 
                        on p.Id equals po.ProductId
                        where po.OrganisationId == id
                        where p.ProductTypeId == (typeId > 0 ? typeId : p.ProductTypeId) //filter by type if specified
                        where p.IsLive
                        select new
                        {
                            Id = p.Id,
                            Name = p.Name,
                            SupplierName = p.Supplier.Name,
                            ProductTypeName = p.ProductType.Name,
                            ShortDescription = p.ShortDescription,
                            ProductTypeId = p.ProductTypeId,
                            DatePublished = p.DatePublished,
                            CurrencyId = p.CurrencyId,

                        })
                        .AsNoTracking()
                        .ToList();

然后像这样查询列表:

List<ProductDetail> finalResult = 
                     myProductList.GroupBy(p => p.ProductTypeName)
                     .SelectMany(d => d.OrderBy(r => r.DatePublished.Take(2))
                     .ToList();

你的解决方案看起来很可靠。我认为它可能在DatePublished上缺少一个“OrderBy”。 - Rich
这对许多情况非常有用且正确,但在我的实际场景中,我并不强制进行类型转换,因为我的结果集实际上具有额外的列,纯粹用于存储计算出的值,稍后我会从中选择并传递到强类型结果集。 - fourbeatcoder

4

对于任何有同样问题的人,我最终解决了它,使用了:

.GroupBy(x => x.ProductTypeId)
.SelectMany(x => x.Take(2))

因此,完整的示例如下:

var productDetails = (from p in products
                            join po in productOrganisations 
                            on p.Id equals po.ProductId
                            where po.OrganisationId == id
                            where p.ProductTypeId == (typeId > 0 ? typeId : p.ProductTypeId) //filter by type if specified
                            where p.IsLive
                            select new
                            {
                                Id = p.Id,
                                Name = p.Name,
                                SupplierName = p.Supplier.Name,
                                ProductTypeName = p.ProductType.Name,
                                ShortDescription = p.ShortDescription,
                                ProductTypeId = p.ProductTypeId,
                                DatePublished = p.DatePublished,
                                CurrencyId = p.CurrencyId,
                            })
                            .GroupBy(x => x.ProductTypeId)
                            .SelectMany(x => x.Take(2))
                            .AsNoTracking()
                            .ToArray();

这个方法是可行的,但是我想知道是否有更好、更高效的方式?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接