Простая генерация гистограммы целочисленных данных на C#
Вопрос
В рамках тестового стенда, который я создаю, я ищу простой класс для вычисления гистограммы целых значений (количество итераций, затраченных алгоритмом для решения задачи).Ответ должен называться примерно так:
Histogram my_hist = new Histogram();
for( uint i = 0; i < NUMBER_OF_RESULTS; i++ )
{
myHist.AddValue( some_result );
}
for( uint j = 0; j < myHist.NumOfBins; j++ )
{
Console.WriteLine( "{0} occurred {1} times", myHist.BinValues[j], myHist.BinCounts[j] );
}
Я был удивлен, что, немного погуглив, не нашел подходящего решения, но, возможно, я искал не то, что нужно.Есть ли какое-то универсальное решение или стоит внедрить мое собственное?
Решение
Вы могли бы использовать SortedDictionary
uint[] items = new uint[] {5, 6, 1, 2, 3, 1, 5, 2}; // sample data
SortedDictionary<uint, int> histogram = new SortedDictionary<uint, int>();
foreach (uint item in items) {
if (histogram.ContainsKey(item)) {
histogram[item]++;
} else {
histogram[item] = 1;
}
}
foreach (KeyValuePair<uint, int> pair in histogram) {
Console.WriteLine("{0} occurred {1} times", pair.Key, pair.Value);
}
Однако при этом останутся пустые мусорные баки
Другие советы
Основываясь на предложении BastardSaint, я придумал аккуратную и довольно универсальную оболочку:
public class Histogram<TVal> : SortedDictionary<TVal, uint>
{
public void IncrementCount(TVal binToIncrement)
{
if (ContainsKey(binToIncrement))
{
this[binToIncrement]++;
}
else
{
Add(binToIncrement, 1);
}
}
}
Так что теперь я могу сделать:
const uint numOfInputDataPoints = 5;
Histogram<uint> hist = new Histogram<uint>();
// Fill the histogram with data
for (uint i = 0; i < numOfInputDataPoints; i++)
{
// Grab a result from my algorithm
uint numOfIterationsForSolution = MyAlorithm.Run();
// Add the number to the histogram
hist.IncrementCount( numOfIterationsForSolution );
}
// Report the results
foreach (KeyValuePair<uint, uint> histEntry in hist.AsEnumerable())
{
Console.WriteLine("{0} occurred {1} times", histEntry.Key, histEntry.Value);
}
Мне потребовалось некоторое время, чтобы разобраться, как сделать его универсальным (для начала я просто отклонил SortedDictionary
конструктор, который означал, что вы могли использовать его только для uint
ключи).
Вы можете использовать Linq:
var items = new[] {5, 6, 1, 2, 3, 1, 5, 2};
items
.GroupBy(i => i)
.Select(g => new {
Item = g.Key,
Count = g.Count()
})
.OrderBy(g => g.Item)
.ToList()
.ForEach(g => {
Console.WriteLine("{0} occurred {1} times", g.Item, g.Count);
});