首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >LINQ查询返回每个类别中价格最高的商品

LINQ查询返回每个类别中价格最高的商品
EN

Stack Overflow用户
提问于 2014-10-15 00:32:30
回答 4查看 3.2K关注 0票数 1

这是对我不久前发布的一个问题的跟进。我得到了一个答案,但我意识到我已经简化了我的示例类,以至于我失去了最初的意图。在接受了原来问题的答案后,我认为最好再开始另一个问题。

这是我的新课:

代码语言:javascript
复制
public class Art
{
    public string Type { get; set; }
    public string Name { get; set; }
    public int Price { get; set; }
}

...and,下面是列表创建:

代码语言:javascript
复制
public static void Example0000()
{
    List<Art> art = new List<Art>();
    art.Add(new Art() { Price = 45, Type = "painting", Name = "Still Life in Maryland" });
    art.Add(new Art() { Price = 123, Type = "sculpture", Name = "Dying Sheep" });
    art.Add(new Art() { Price = 12, Type = "icon", Name = "Perplexed Smiley" });
    art.Add(new Art() { Price = 460, Type = "sculpture", Name = "Waves on Sand" });
    art.Add(new Art() { Price = 2030, Type = "painting", Name = "Robert in the Morning" });
    art.Add(new Art() { Price = 10, Type = "icon", Name = "Smiley Picking Nose" });
    art.Add(new Art() { Price = 700, Type = "painting", Name = "Birds in Autumn" });
    art.Add(new Art() { Price = 1400, Type = "sculpture", Name = "Holding Hands" });
    art.Add(new Art() { Price = 46, Type = "painting", Name = "Reeling Him In" });
    art.Add(new Art() { Price = 12000, Type = "sculpture", Name = "Old Dog" });
    art.Add(new Art() { Price = 6, Type = "icon", Name = "Hiding Smiley" });
    art.Add(new Art() { Price = 810, Type = "sculpture", Name = "Rhinestone Cowgirl" });
    art.Add(new Art() { Price = 250, Type = "painting", Name = "Upstairs, Downstairs" });
    art.Add(new Art() { Price = 3, Type = "icon", Name = "Dopey Smiley" });
    art.Add(new Art() { Price = 1000, Type = "painting", Name = "Young Love" });
    art.Add(new Art() { Price = 260, Type = "sculpture", Name = "Taking a Spill" });
}

我想要的是一个对象集合,每个类型都有一个对象,它们有三个属性: ArtType、ArtName和MostExpensivePrice。对于每种类型,我想要的名称和价格的最高价格的项目的类型。

所以我的清单应该是:

painting______Robert_in_the_Morning______2030

sculpture_____Old Dog__________________12000

icon_________Perplexed Smiley______________12

那么LINQ会是什么样的呢?我开始的示例如下所示:

代码语言:javascript
复制
var categories4 =
    from a in art
    group a by a.Type into g
    let maxPrice = g.Max(p => p.Price)
    select new { ArtType = g.Key, MostExpensive = g.Where(a => a.Price == maxPrice) };
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-10-15 00:46:42

请参见Enumerable.Aggregate()方法。

到目前为止,给出的另一个答案只是返回最高价格,这不是你在这里要求的。如果您像这样使用Enumerable.Aggregate():

代码语言:javascript
复制
MostExpensive = g.Aggregate((art1, art2) => (art1.Price > art2.Price) ? art1 : art2)

然后,LINQ结果将包含Art实例,而不是int实例,因此您可以以最大值而不是仅显示价格来显示所有信息。

编辑:

如果上面的内容并不明显,那么完整的表达式可以是:

代码语言:javascript
复制
var artprices =
    from a in art
    group a by a.Type into g
    let mostExpensive = g.Aggregate((art1, art2) => (art1.Price > art2.Price) ? art1 : art2)
    select new { ArtType = g.Key, ArtName = mostExpensive.Name, MostExpensivePrice = mostExpensive.Price };

你会得到一个结果,元素有你想要的三个值。

编辑2:

最后,作为新的网站,我不能添加评论到其他答案,但我会尽可能客观地指出,他们都有缺陷,以不同的方式。

一个答案是,对原始集合中的每个元素进行一次评估,然后对每个Type值(即每个组)进行一次评估。这是一个典型的O(N^2)场景,它将在非常小的数据集上执行得很好,但是对于任何非平凡的数据集合来说都是非常糟糕的。

另外两个答案建议对每一组中的元素进行排序。这样做更好,但仍然需要该排序的内存和性能开销。典型的排序是O(N log N),这比O(N^2)好得多,但仍然不如使用聚合()获得的线性O(N)好。同样,小数据集完全没有问题,但是与更有效的方法相比,一个非平凡的集合将导致显着的性能下降。

希望这能帮上忙!

票数 1
EN

Stack Overflow用户

发布于 2014-10-15 01:38:12

这个对你有用吗?

代码语言:javascript
复制
var query =
    art
        .OrderByDescending(x => x.Price)
        .GroupBy(x => x.Type)
        .Select(x => x.First());

我得到了这个结果:

票数 2
EN

Stack Overflow用户

发布于 2014-10-15 01:02:54

好吧,你把第一部分说对了,你只是有点偏离了第二部分。您需要做的第一件事是了解GroupBy方法返回的内容。GroupBy本质上返回列表列表(数组数组或可枚举的可枚举列表)。

使用声明为您的类型是:

代码语言:javascript
复制
public class Art
{
    public string Type { get; set; }
    public string Name { get; set; }
    public int Price { get; set; }
}

根据这些数据:

代码语言:javascript
复制
List<Art> art = new List<Art>()
{
    new Art() { Price = 45, Type = "painting", Name = "Still Life in Maryland" }),
    new Art() { Price = 123, Type = "sculpture", Name = "Dying Sheep" }),
    new Art() { Price = 12, Type = "icon", Name = "Perplexed Smiley" }),
    new Art() { Price = 460, Type = "sculpture", Name = "Waves on Sand" });,
    new Art() { Price = 2030, Type = "painting", Name = "Robert in the Morning" }),
    new Art() { Price = 10, Type = "icon", Name = "Smiley Picking Nose" }),
    new Art() { Price = 700, Type = "painting", Name = "Birds in Autumn" }),
    new Art() { Price = 1400, Type = "sculpture", Name = "Holding Hands" }),
    new Art() { Price = 46, Type = "painting", Name = "Reeling Him In" }),
    new Art() { Price = 12000, Type = "sculpture", Name = "Old Dog" }),
    new Art() { Price = 6, Type = "icon", Name = "Hiding Smiley" }),
    new Art() { Price = 810, Type = "sculpture", Name = "Rhinestone Cowgirl" }),
    new Art() { Price = 250, Type = "painting", Name = "Upstairs, Downstairs" }),
    new Art() { Price = 3, Type = "icon", Name = "Dopey Smiley" }),
    new Art() { Price = 1000, Type = "painting", Name = "Young Love" }),
    new Art() { Price = 260, Type = "sculpture", Name = "Taking a Spill" })
}

将艺术品列表分组,结果如下所示:

代码语言:javascript
复制
IEnumerable<IGrouping<string, Art>> groupedByType = art.GroupBy(a => a.Type);

其中,每个IGrouping<string, Art>包含一个Art列表,其中列表中的每个部分都具有相同的Type。在第二步中,我们只需要从每一组中选择最高价格:

代码语言:javascript
复制
IEnumerable<Art> maxFromEachGroup = groupedByType
    // Take a single piece of art from each group
    .Select(group =>
        // Get the maximum piece of art by ordering from largest to smallest 
        // and taking the first
        group.OrderByDescending(a => a.Price).First() 
    );

现在您有了一个Art列表,其中包含了每个组中最昂贵的部分。使用最大值需要注意的是,它返回最高价格的值,而不是以最大价格返回Art的部分。因此,LINQ表达式表单中的整个表达式是:

代码语言:javascript
复制
var maxFromEachGroup = from a in art
                       group a by a.Type into g
                       select (from a in g orderby a.Price descending select a).First();
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26372606

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档