2011-02-02 8 views
17

Digamos que hayan siguientes datos:Como llegar distinta con alto valor utilizando LINQ

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

Quiero obtener la lista de nombres distintos con más alta prioridad, por lo que el resultado será similar:

Name Priority 
A  5 
B  1 
C  3 

¿Cómo puedo usar Linq para hacer eso?

Respuesta

17
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); 
} 
+2

No estoy seguro si usted es consciente, pero LINQPad es ideal para este tipo de fragmentos rápidos. –

+1

Buena idea usar con la sobrecarga de GroupBy que requiere una proyección. Es una pena que no haya un método de extensión MaxBy y tenemos que recurrir a un agregado. –

+0

@Martinho, podemos resolver esto sin agregado y usando max, verifique mi respuesta .... – RameshVel

5

He aquí un enfoque alternativo:

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

O si lo prefiere el uso de la sintaxis de 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(); 
+1

Solo señalando que la primera versión es O (N^2), lo cual es horrible para algo que se puede hacer en O (N). La segunda versión no es equivalente a la primera y se ejecuta en O (N). Ambos producen duplicados si hay alguno en la entrada. –

+0

@MartinhoFernandes Tienes toda la razón sobre los duplicados, corregí mi respuesta. Puedo ver que la primera consulta es O (N^2), pero ¿cómo se verifica que la segunda consulta se ejecuta en O (N)? ¿Analizaste el MSIL? –

+2

tipo de. ¿Conoces a [LinqPad] (http://www.linqpad.net/)? Eso es lo que uso para probar estas piezas de código. Cambié 'del ítem en ítems' a' del ítem en ítems.AsQueryable() ', agregué' results.Dump() 'al final, y luego miré el panel" λ "a continuación. Muestra la consulta tal como se tradujo de la sintaxis de la expresión de consulta a la sintaxis lambda normal. Es más fácil (al menos para mí) evaluar la complejidad observando eso. Si quieres ver el IL, puedes, pero se ve mucho mejor en C#;) –

2

Otro enfoque simple y sin agregar

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

Actualización:

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

Sé que la pregunta no lo hace explícito, pero tenga en cuenta que esta solución produce datos de un tipo diferente de la fuente. –

+0

@Martinho, tienes razón. todavía podemos solucionarlo mediante OrderByDescending sin agregado ...... – RameshVel

+1

que funciona, pero tenga en cuenta que aumenta el tiempo de ejecución de O (N) a O (N log N). –

Cuestiones relacionadas