Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple LINQ question in C#

Tags:

c#

.net

linq

I am trying to use LINQ to return the an element which occurs maximum number of times AND the number of times it occurs.

For example: I have an array of strings:

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

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

In this array, the query would return cherry as the maximum occurred element, and 3 as the number of times it occurred. I would also be willing to split them into two queries if that is necessary (i.e., first query to get the cherry, and second to return the count of 3.

like image 606
Brett Avatar asked Feb 03 '11 16:02

Brett


3 Answers

The solutions presented so far are O(n log n). Here's an O(n) solution:

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

This needs a definition of MaxBy. Here is one:

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;                
    }
}
like image 72
jason Avatar answered Nov 15 '22 12:11

jason


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

And in case if we don't like O(N log N):

var topWordGroup = words.GroupBy(word => word).Aggregate((current, acc) => current.Count() < acc.Count() ? acc : current);
like image 23
Snowbear Avatar answered Nov 15 '22 13:11

Snowbear


First thing that comes to mind (meaning there is probably a more efficient way)

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

EDIT: forgot op wanted the name and the count

like image 40
diceguyd30 Avatar answered Nov 15 '22 13:11

diceguyd30