2011-02-03 11 views
5

Estoy tratando de usar LINQ para devolver el elemento que ocurre el número máximo de veces Y el número de veces que ocurre.Pregunta simple de LINQ en C#

Por ejemplo: tengo una matriz de cadenas:

string[] words = { "cherry", "apple", "blueberry", "cherry", "cherry", "blueberry" }; 

//... 
Some LINQ statement here 
//... 

En esta matriz, la consulta volvería cherry como el máximo elemento se produjo, y 3 como el número de veces que se haya producido. Yo también estaría dispuesto a dividirlas en dos consultas si es necesario (es decir, primera consulta para obtener el cherry, y el segundo para devolver el recuento de 3.

Respuesta

8
var topWordGroup = words.GroupBy(word => word).OrderByDescending(group => group.Count()).FirstOrDefault(); 
// topWordGroup might be a null! 
string topWord = topWordGroup.Key; 
int topWordCount = topWordGroup.Count; 

Y en caso de que si no nos gusta O(N log N):

var topWordGroup = words.GroupBy(word => word).Aggregate((current, acc) => current.Count() < acc.Count() ? acc : current); 
+2

Esto es 'O (n log n)' cuando 'O (n)' es posible: http://stackoverflow.com/questions/4888537/simple-linq-question-in-c/4888703#4888703. – jason

4

primera cosa que viene a la mente (es decir, hay probablemente una manera más eficiente)

var item = words.GroupBy(x => x).OrderByDescending(x => x.Count()).First() 
//item.Key is "cherry", item.Count() is 3 

EDITAR: olvidó op quería el nombre y el recuento

+1

Esto es 'O (n log n) cuando' O (n) 'es posible: http://stackoverflow.com/questions/48885 37/simple-linq-question-in-c/4888703 # 4888703. – jason

+0

@Jason Ha! ¡Nos encontremos de nuevo! Y una vez más estás en lo correcto. Había pasado por alto el uso de MoreLinq de Jon Skeet – diceguyd30

+0

¿Cuál es Jon MoreLinq de Jon? He visto su MiscUtil, pero nunca MoreLinq. – jason

1
string[] words = { "cherry", "apple", "blueberry", "cherry", "cherry", "blueberry" }; 

var topWordAndCount=words 
    .GroupBy(w=>w) 
    .OrderByDescending(g=>g.Count()) 
    .Select(g=>new {Word=g.Key,Count=g.Count()}) 
    .FirstOrDefault(); 

//if(topWordAndCount!=null) 
//{ 
// topWordAndCount.Word 
// topWordAndCount.Count 
+1

Esto es 'O (n log n)' cuando 'O (n)' es posible: http: // stackoverflow.com/questions/4888537/simple-linq-question-in-c/4888703 # 4888703. – jason

0
string[] words = { "cherry", "apple", "blueberry", "cherry", "cherry", "blueberry" }; 

var r = words.GroupBy (x => x) 
      .OrderByDescending (g => g.Count()) 
      .FirstOrDefault(); 
Console.WriteLine (String.Format ("The element {0} occurs {1} times.", r.Key, r.Count())); 
12

Las soluciones presentadas hasta ahora son O(n log n). Aquí es una solución O(n):

var max = words.GroupBy(w => w) 
       .Select(g => new { Word = g.Key, Count = g.Count() }) 
       .MaxBy(g => g.Count); 
Console.WriteLine(
    "The most frequent word is {0}, and its frequency is {1}.", 
    max.Word, 
    max.Count 
); 

Esto necesita una definición de MaxBy. He aquí uno:

public static TSource MaxBy<TSource>(
    this IEnumerable<TSource> source, 
    Func<TSource, IComparable> projectionToComparable 
) { 
    using (var e = source.GetEnumerator()) { 
     if (!e.MoveNext()) { 
      throw new InvalidOperationException("Sequence is empty."); 
     } 
     TSource max = e.Current; 
     IComparable maxProjection = projectionToComparable(e.Current); 
     while (e.MoveNext()) { 
      IComparable currentProjection = projectionToComparable(e.Current); 
      if (currentProjection.CompareTo(maxProjection) > 0) { 
       max = e.Current; 
       maxProjection = currentProjection; 
      } 
     } 
     return max;     
    } 
} 
+1

Una vez más, +1 para el O (n)! – diceguyd30

+2

También puede sustituir 'Aggregate' por' MaxBy' si es necesario, aunque 'MaxBy' es * mucho * más agradable:' var max = words.GroupBy (x => x, (k, g) => new {Word = k , Count = g.Count()}). Aggregate ((a, x) => (x.Count> a.Count)? X: a); ' – LukeH

+0

¡Chicos! GroupBy no es lineal. Hay una pequeña penalización por colisiones hash. Estoy inventando esto, pero es algo así como O (n * log log n) –

0

A O más simple (n) solución:

var groups = words.GroupBy(x => x); 
var max = groups.Max(x => x.Count()); 
var top = groups.First(y => y.Count() == max).Key; 
0

Aquí está una junta muy rápida solución (n) en una línea (!):

s.GroupBy(x => x).Aggregate((IGrouping<string,string>)null, (x, y) => (x != null && y != null && x.Count() >= y.Count()) || y == null ? x : y, x => x); 

O esto:

s.GroupBy(x => x).Select(x => new { Key = x.Key, Count = x.Count() }).Aggregate(new { Key = "", Count = 0 }, (x, y) => x.Count >= y.Count ? x : y, x => x);