按C#中元素的频率对数组进行排序

Sorting array by frequency of elements in C#

这是我目前的情况

int[] numbers = { 3,5,4,3,8,8,5,3,2,1,9,5 };
int[] n = new int[12];
int[] k;

foreach (int number in numbers)
{
    n[number]++;
}
Array.Sort(n);
Array.Reverse(n);

foreach (int value in n)
{
    Console.WriteLine(value);
}

我知道我遗漏了计算元素频率后对其进行排序的部分,我只是无法理解它。非常感谢您的帮助,谢谢!

What's the problem with your solution ?

尽管您在代码中正确地保留了 table 中称为 n 的数字的频率,因此我将其称为 frequencies,那么您 Sort这个数组。此操作会破坏您的解决方案,因为每个频率都与其在数组中位置的相应索引相关联。

例如如果这个数组的一个实例是这个[8,2,1,7,6]。当您对该数组调用 Sort 方法时,结果数组将被排序,数组元素的顺序将是 [1,2,7,6,8]。在调用sort之前,数组的第一个元素表示数字0(第一个元素的索引为0)在我们的numbers中被找到了8次。排序后,第一个元素是1,也就是说现在0号出现的频率是1,显然是错误的。

如果你想保持你的方式,那么你可以尝试这样的事情:

int[] numbers = {  1,2,2,9,1,2,5,5,5,5,2 };
int[] frequencies = new int[12];
int k = 3;

foreach (int number in numbers)
{
    frequencies[number]++;
}

var mostFrequentNumbers = frequencies.Select((frequency, index) => new 
                                            { 
                                                Number = index,
                                                Frequency = frequency
                                            })
                                      .OrderByDescending(item => item.Frequency)
                                      .Select(item => item.Number)
                                      .Take(k);

foreach (int mostFrequentNumber in mostFrequentNumbers)
{
   Console.WriteLine(mostFrequentNumber);
}

Are there any other approaches ?

一个简单的方法是使用像字典这样的数据结构,在其中您可以将数字作为键,将相应的频率作为相应的值。

然后你可以按降序对上述数据结构进行排序,并保留 k 个最频繁出现的数字。

int[] numbers = { 1,2,2,9,1,2,5,5,5,5,2 };
int k = 3;

Dictionary<int, int> numberFrequencies = new Dictionary<int, int>();

foreach (int number in numbers)
{
    if(numberFrequencies.ContainsKey(number))
    {
        numberFrequencies[number] += 1;
    }
    else
    {
            numberFrequencies.Add(number, 1);
    }
}


var mostFrequentNumbers = numberFrequencies.OrderByDescending(numberFrequency => numberFrequency.Value)
                                           .Take(k)
                                           .Select(numberFrequency => numberFrequency.Key);


foreach (int mostFrequentNumber in mostFrequentNumbers)
{
    Console.WriteLine(mostFrequentNumber);
}

您也可以仅使用 LINQ 实现相同的目的:

int[] numbers = { 1,2,2,9,1,2,5,5,5,5,2 };
int k = 3;

var mostFrequentNumbers = numbers.GroupBy(number => number)
                                 .ToDictionary(gr => gr.Key, gr => gr.Count())
                                 .OrderByDescending(keyValue => keyValue.Value)
                                 .Take(k)
                                 .Select(numberFrequency => numberFrequency.Key);


foreach (int mostFrequentNumber in mostFrequentNumbers)
{
    Console.WriteLine(mostFrequentNumber);
}

您可以只使用 Linq 扩展:

using System.Linq;
using System.Collections.Generic;

...

private static IEnumerable<int> Solve(int[] numbers, int k) {
    return numbers
        .GroupBy(x => x)
        .OrderByDescending(g => g.Count())
        .Select(g => g.Key)
        .Take(k);
}

那么您可以拨打:

var numbers = new []{1,2,2,9,1,2,5,5,5,5,2};
var k = 3;
var result = Solve(numbers, k);
foreach (int n in result)
    Console.WriteLine(n);

非常简洁:

var frequents = numbers.GroupBy(t => t)
    .Where(grp => grp.Count() > 1)
    .Select(t => t.Key)
    .OrderByDescending(t => t)
    .Take(k)
    .ToList();