如何在一个Int数组中获取最常见的值? (C#)

15

如何使用C#获取Int数组中出现最频繁的值

例如:数组包含以下值:1、1、1、2

答案应该是1


你的整数值域有限制吗?比如说,所有的值都在0到10之间吗? - Michael Petito
@Michael Petito:是的。如果范围不太大,可以非常快地完成。 - Mike Dunlavey
所有的int都是正数且值不大于5。 - mouthpiec
我认为应该有像 .Average() 或 .Max() 这样的函数。 - mouthpiec
如果你只有5个不同的值,那么你可以很容易地使用一个数组来存储每个值的计数器,并在输入数组上循环一次。这非常类似于Guffa的解决方案,只是因为你的键是小整数,所以不需要字典。 - Michael Petito
显示剩余2条评论
6个回答

28
var query = (from item in array
        group item by item into g
        orderby g.Count() descending
        select new { Item = g.Key, Count = g.Count() }).First();

如果只想获取值而不是计数,可以使用以下方式:

var query = (from item in array
                group item by item into g
                orderby g.Count() descending
                select g.Key).First();

第二个版本是使用 Lambda 表达式:

var query = array.GroupBy(item => item).OrderByDescending(g => g.Count()).Select(g => g.Key).First();

1
这不是在进行O(nlogn)排序吗? - liori
2
@liori:是的。排序不是找到最高计数的最有效方法。 - Guffa
我更喜欢使用.First().Key而不是自己使用Select - juharr

15

一些老式但高效的循环:

var cnt = new Dictionary<int, int>();
foreach (int value in theArray) {
   if (cnt.ContainsKey(value)) {
      cnt[value]++;
   } else {
      cnt.Add(value, 1);
   }
}
int mostCommonValue = 0;
int highestCount = 0;
foreach (KeyValuePair<int, int> pair in cnt) {
   if (pair.Value > highestCount) {
      mostCommonValue = pair.Key;
      highestCount = pair.Value;
   }
}

现在mostCommonValue包含最常见的值,而highestCount包含它出现的次数。


2
+1 没有什么不对的,尽管使出浑身解数把它完成。 - Anthony Pegram
第二部分可以通过使用MaxBy()来简化。很遗憾它实际上不在LINQ中(但它在MoreLinq中)。 - svick

4
我知道这篇文章有点旧了,但今天有人问我一个与此问题相反的问题。
LINQ分组
sourceArray.GroupBy(value => value).OrderByDescending(group => group.Count()).First().First();

临时集合,类似于Guffa的:

var counts = new Dictionary<int, int>();
foreach (var i in sourceArray)
{
    if (!counts.ContainsKey(i)) { counts.Add(i, 0); }
    counts[i]++;
}
return counts.OrderByDescending(kv => kv.Value).First().Key;

2
  public static int get_occure(int[] a)
    {
        int[] arr = a;
        int c = 1, maxcount = 1, maxvalue = 0;
        int result = 0;
        for (int i = 0; i < arr.Length; i++)
        {
            maxvalue = arr[i];
            for (int j = 0; j <arr.Length; j++)
            {

                if (maxvalue == arr[j] && j != i)
                {
                    c++;
                    if (c > maxcount)
                    {
                        maxcount = c;
                        result = arr[i];

                    }
                }
                else
                {
                    c=1;

                }

            }


        }
        return result;
    }

1
另一种使用linq的解决方案:
static int[] GetMostCommonIntegers(int[] nums)
{
    return nums
            .ToLookup(n => n)
            .ToLookup(l => l.Count(), l => l.Key)
            .OrderBy(l => l.Key)
            .Last() 
            .ToArray();
}   

这个解决方案可以处理多个数字出现次数相同的情况:

[1,4,5,7,1] => [1]
[1,1,2,2,3,4,5] => [1,2]
[6,6,6,2,2,1] => [6]

1

可能是O(n log n),但速度很快:

sort the array a[n]

// assuming n > 0
int iBest = -1;  // index of first number in most popular subset
int nBest = -1;  // popularity of most popular number
// for each subset of numbers
for(int i = 0; i < n; ){
  int ii = i; // ii = index of first number in subset
  int nn = 0; // nn = count of numbers in subset
  // for each number in subset, count it
  for (; i < n && a[i]==a[ii]; i++, nn++ ){}
  // if the subset has more numbers than the best so far
  // remember it as the new best
  if (nBest < nn){nBest = nn; iBest = ii;}
}

// print the most popular value and how popular it is
print a[iBest], nBest

你一开始没说要排序数组 :). 无论如何,如果你要排序的话,可以更简单地实现。一个for循环和几个变量就足够了。 - IVlad
@IVlad:那不是第一行代码吗?无论如何,你是对的。 - Mike Dunlavey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接