【问题标题】:LINQ Using Max() to select a single rowLINQ 使用 Max() 选择单行
【发布时间】:2012-02-02 15:22:04
【问题描述】:

我在从 NHibernate 返回的 IQueryable 上使用 LINQ,我需要在几个字段中选择具有最大值的行。

我已经简化了我坚持的那一点。我需要从表格中选择一个字段中具有最大值的一行。

var table = new Table { new Row(id: 1, status: 10), new Row(id: 2, status: 20) }

from u in table
group u by 1 into g
where u.Status == g.Max(u => u.Status)
select u

这是不正确的,但我无法计算出正确的表格。

顺便说一句,我实际上想要达到的目标大致是这样的:

var clientAddress = this.repository.GetAll()
    .GroupBy(a => a)
    .SelectMany(
            g =>
            g.Where(
                a =>
                a.Reference == clientReference && 
                a.Status == ClientStatus.Live && 
                a.AddressReference == g.Max(x => x.AddressReference) && 
                a.StartDate == g.Max(x => x.StartDate)))
    .SingleOrDefault();

我从上面的 lambda 开始,但我一直在使用 LINQPad 来尝试找出选择 Max() 的语法。

更新

删除 GroupBy 是关键。

var all = this.repository.GetAll();

var address = all
            .Where(
                a =>
                a.Reference == clientReference && 
                a.Status == ClientStatus.Live && 
                a.StartDate == all.Max(x => x.StartDate) &&
                a.AddressReference == all.Max(x => x.AddressReference))
            .SingleOrDefault();

【问题讨论】:

标签: c# .net linq


【解决方案1】:

我不明白你为什么在这里分组。

试试这个:

var maxValue = table.Max(x => x.Status)
var result = table.First(x => x.Status == maxValue);

只迭代一次table 的另一种方法是:

var result = table.OrderByDescending(x => x.Status).First();

如果table 是内存中不存在的IEnumerable<T> 或动态计算的IEnumerable<T>,这将很有帮助。

【讨论】:

  • 我取出分组,发现我可以让它工作:from u in User_Accounts where u.Status == User_Accounts.Max(y => y.Status) select u
  • 也可以嵌套 lambda 语法:table.First(x => x.Status == table.Max(x => x.Status))
  • @LandonPoch:这不是一个好主意,因为这将计算最大 N 次,其中 N 是 table 中的项目数。
  • @Daniel Hilgarth:好收获!这实际上会计算表中每一行的最大值。我的错。
【解决方案2】:

你也可以这样做:

(from u in table
orderby u.Status descending
select u).Take(1);

【讨论】:

    【解决方案3】:

    您可以按状态分组并从最大的组中选择一行:

    table.GroupBy(r => r.Status).OrderByDescending(g => g.Key).First().First();
    

    第一个First()得到第一组(状态最大的行集合);第二个First() 获得该组中的第一行。
    如果状态总是 unqiue,可以将第二个First() 替换为Single()

    【讨论】:

      【解决方案4】:

      解决第一个问题,如果您需要将几行按某些标准分组,另一列具有最大值,您可以执行以下操作:

      var query =
          from u1 in table
          join u2 in (
              from u in table
              group u by u.GroupId into g
              select new { GroupId = g.Key, MaxStatus = g.Max(x => x.Status) }
          ) on new { u1.GroupId, u1.Status } equals new { u2.GroupId, Status = u2.MaxStatus}
          select u1;
      

      【讨论】:

        【解决方案5】:

        这个想法怎么样: 比这个好

        1. 选择最大值
        2. 按最大值选择
        
        var maxRow = table.Aggregate(
          (a, b) => a.Status > b.Status ? a : b  // whatever you need to compare
        );
        

        【讨论】:

          【解决方案6】:

          再举一个例子:

          关注:

           qryAux = (from q in qryAux where
                      q.OrdSeq == (from pp in Sessao.Query<NameTable>() where pp.FieldPk
                      == q.FieldPk select pp.OrdSeq).Max() select q);
          

          等于:

           select t.*   from nametable t  where t.OrdSeq =
                  (select max(t2.OrdSeq) from nametable t2 where t2.FieldPk= t.FieldPk)
          

          【讨论】:

            【解决方案7】:

            只需一行:

            var result = table.First(x => x.Status == table.Max(y => y.Status));
            

            注意有两个动作。 内部动作是为了找到最大值, 外部操作是为了获取所需的对象。

            【讨论】:

            • 此方法在 cmets 中讨论到接受的答案,但指出这是一个坏主意。
            • 这是个坏主意,因为 table.Max(y => y.Status) 将为表中的每个项目调用一次,这远非最优。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-17
            • 2013-09-11
            • 1970-01-01
            相关资源
            最近更新 更多