【问题标题】:How to get distinct with highest value using Linq如何使用 Linq 获得最高价值
【发布时间】:2011-02-02 11:37:05
【问题描述】:

假设我有以下数据:

Name    Priority
A       3
A       5
B       1
C       1
C       3
C       2

我想获取具有最高优先级的不同名称列表,因此结果如下所示:

Name    Priority
A       5
B       1
C       3

我如何使用 Linq 来做到这一点?

【问题讨论】:

    标签: c# linq


    【解决方案1】:
    var query = yourData
        .GroupBy(x => x.Name,
                 (k, g) => g.Aggregate((a, x) => (x.Priority > a.Priority) ? x : a));
    
    // and a quick test...
    foreach (var result in query)
    {
        Console.WriteLine(result.Name + " " + result.Priority);
    }
    

    【讨论】:

    • 不确定你是否知道,但 LinqPad 非常适合这种快速的 sn-ps。
    • 与进行投影的 GroupBy 重载一起使用是个好主意。只是可惜没有 MaxBy 扩展方法,我们不得不求助于聚合。
    • @Martinho,我们可以在没有聚合和使用最大值的情况下解决这个问题,检查我的答案....
    • @Ramesh:如果您想从输入返回对象而不是创建新对象,则无法使用 max 解决它。
    • @Martinho,你是对的..我们需要使用一些投影来获取源对象..
    【解决方案2】:

    这是一个替代方法:

    var items = new List<Tuple<string, int>>()
    {
        Tuple.Create("A", 3),
        Tuple.Create("A", 5),
        Tuple.Create("B", 1),
        Tuple.Create("C", 1),
        Tuple.Create("C", 3),
        Tuple.Create("C", 2)
    };
    
    var results = items.GroupBy(i => i.Item1)
                       .SelectMany(g => g
                           .Where(i => i.Item2 == g.Max(m => m.Item2)))
                       .Distinct();
    

    或者,如果您更喜欢使用 C# LINQ 语法:

    results = (from item in items
               group item by item.Item1 into groupedItems
               let maxPriority = groupedItems.Max(item => item.Item2)
               from element in groupedItems
               where element.Item2 == maxPriority
               select element).Distinct();
    

    【讨论】:

    • 只是注意到第一个版本是 O(N^2),这对于可以在 O(N) 中完成的事情来说是很糟糕的。第二个版本不等同于第一个版本,运行时间为 O(N)。如果输入中有任何重复项,则两者都会产生重复项。
    • @MartinhoFernandes 您对重复项完全正确,我更正了我的答案。我可以看到第一个查询是 O(N^2),但是您如何验证第二个查询在 O(N) 中运行?你分析过 MSIL 吗?
    • 有点。你知道LinqPad吗?这就是我用来测试这些代码的方法。我把from item in items改成from item in items.AsQueryable(),最后加上results.Dump(),然后看下面的“λ”面板。它显示了从查询表达式语法转换为常规 lambda 语法的查询。通过查看它来评估复杂性更容易(至少对我而言)。如果您想查看 IL,可以,但在 C# 中看起来要好得多;)
    • @Martinho 我对所有代码示例都使用 LinqPad :) 但是我从未想过使用“Lambda”面板来评估使用 C#/VB 语法的 LINQ 查询的复杂性。我以后肯定会这样做的;)
    • Enrico,我正在尝试使用您的 linq(LINQ 语法中的第二个示例。)但是我得到了重复。你知道我将如何消除重复吗?
    【解决方案3】:

    另一种无需聚合的简单方法

            var listNP = new List<NP>()
              {
                  new NP() {name="A",priority=3},
                  new NP() {name="A",priority=5},
                  new NP() {name="b",priority=1},
                  new NP() {name="b",priority=1},
                  new NP() {name="c",priority=3},
                  new NP() {name="c",priority=2},
              };
    
              var np = listNP.GroupBy(x => x.name).Select(y => new
              {
                  name = y.Key,
                  max =  y.Max(x=>x.priority)
    
              }).ToList();
    

    更新:

    var np = listNP.GroupBy(x => x.name)
               .Select(y => y.OrderByDescending(z => z.priority).First()).ToList();
    

    【讨论】:

    • 我知道问题并没有明确说明,但请注意,此解决方案会生成与源不同类型的数据。
    • @Martinho,你是对的。我们仍然可以通过 OrderByDescending 修复它而不用聚合......
    • 可行,但请注意,它将执行时间从 O(N) 提高到 O(N log N)。
    • @Martinho,是的,我们也需要考虑这一点:)
    猜你喜欢
    • 1970-01-01
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-20
    相关资源
    最近更新 更多