LINQ Usando Max () para seleccionar una sola fila


95

Estoy usando LINQ en un IQueryable devuelto por NHibernate y necesito seleccionar la fila con los valores máximos en un par de campos.

He simplificado la parte en la que me quedo. Necesito seleccionar la fila de mi tabla con el valor máximo en un campo.

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

Esto es incorrecto pero no puedo encontrar la forma correcta.

Por cierto, lo que en realidad estoy tratando de lograr es aproximadamente esto:

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();

Comencé con la lambda anterior, pero he estado usando LINQPad para intentar resolver la sintaxis para seleccionar Max ().

ACTUALIZAR

Eliminar el GroupBy fue clave.

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();


@ M.Babcock hubo una buena respuesta bastante abajo en esa pregunta: stackoverflow.com/a/6330485/444244
Boggin

Hay mucho mejores que ese ...
M.Babcock

Eche un vistazo a la respuesta .
Sergey Brunov

@Serge Estoy de acuerdo en que morelinq sería lo mejor, pero me temo que este proyecto tiene impedimentos para agregar nuevas bibliotecas.
Boggin

Respuestas:


230

No veo por qué se está agrupando aquí.

Prueba esto:

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

Un enfoque alternativo que repetiría table solo una vez sería este:

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

Esto es útil si tablees una IEnumerable<T>que no está presente en la memoria o que se calcula sobre la marcha.


1
from u in User_Accounts where u.Status == User_Accounts.Max(y => y.Status) select u
Saqué

1
También puede anidar la sintaxis lambda: table.First(x => x.Status == table.Max(x => x.Status))
Landon Poch

13
@LandonPoch: Esa no es una buena idea, ya que esto calcularía el máximo de N veces siendo N el número de elementos en table.
Daniel Hilgarth

2
@Daniel Hilgarth: ¡Buen partido! De hecho, eso calcularía el máximo por cada fila de la tabla. Culpa mía.
Landon Poch

17

También puedes hacer:

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

13

Puede agrupar por estado y seleccionar una fila del grupo más grande:

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

El primero First()obtiene el primer grupo (el conjunto de filas con el estado más grande); el segundo First()obtiene la primera fila de ese grupo.
Si el estado siempre es único, puede reemplazar el segundo First()con Single().


7

Abordando la primera pregunta, si necesita tomar varias filas agrupadas por ciertos criterios con la otra columna con valor máximo, puede hacer algo como esto:

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;

0

Más un ejemplo:

Seguir:

 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);

Igual a:

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

-1

Simplemente en una línea:

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

Observe que hay dos acciones. la acción interna es para encontrar el valor máximo, la acción externa es para obtener el objeto deseado.


Este método se discutió en los comentarios a la respuesta aceptada donde se señaló que era una mala idea.
Boggin
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.