2011-02-03 33 views
5

我正在尝试使用LINQ来返回出现最大次数和发生次数的元素。C#中的简单LINQ问题#

例如: 我有一个字符串数组:

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

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

在此阵列中,该查询将返回cherry作为发生元件的最大和3作为其发生次数。我也愿意将它们分成两个查询,如果这是必要的(第一查询来获得cherry,二来回报3计数。

回答

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; 

而在情况下,如果我们不喜欢O(N log N)

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

我想到的第一件事情(指有可能是一个更有效的方式)

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

编辑:忘记运想要的名称计数

+1

这是`O(n日志n)当`O(n)`是可能的:http://stackoverflow.com/questions/48885/37 /简单LINQ的问题 - 在-C 4888703#4888703。 – jason 2011-02-03 16:26:01

+0

@Jason Ha!我们再见面!再一次你是对的。我忽略了使用Jon Skeet的MoreLinq – diceguyd30 2011-02-03 16:32:26

+0

Jon的MoreLinq是什么?我见过他的MiscUtil,但从来没有见过MoreLinq。 – jason 2011-02-03 16:36:50

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

提出的解决方案至今都O(n log 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 
); 

这需要的MaxBy的定义。这里是一个:

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;     
    } 
} 
0

一个更简单的O(n)的解决方案:在一行

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

这里是一个非常快的O(N)解决方案(!):

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

或者这个:

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