2009-05-29 109 views
8

Como parte de un banco de prueba que estoy construyendo, estoy buscando una clase simple para calcular un histograma de valores enteros (número de iteraciones tomadas para un algoritmo para resolver un problema) . La respuesta debería llamarse algo como esto:Generación de histograma simple de datos enteros en 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]); 
} 

Me sorprendió un poco de google no se presentó una buena solución, pero tal vez no buscar las cosas correctas. ¿Existe una solución genérica o vale la pena hacerla mía?

Respuesta

12

Usted podría utilizar 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); 
} 

Esto dejará a cabo contenedores vacíos, aunque

+0

+1: Parece un buen comienzo. Da la casualidad, solo me interesan los contenedores que contienen datos :-) –

6

Sobre la base de la sugerencia de BastardSaint me ocurrió con un limpio y bastante genérico envoltorio:

public class Histogram<TVal> : SortedDictionary<TVal, uint> 
{ 
    public void IncrementCount(TVal binToIncrement) 
    { 
     if (ContainsKey(binToIncrement)) 
     { 
      this[binToIncrement]++; 
     } 
     else 
     { 
      Add(binToIncrement, 1); 
     } 
    } 
} 

Así ahora puedo hacerlo:

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

Me tomó un tiempo encontrar la manera de hacerlo genérico (para empezar, simplemente eliminé el constructor SortedDictionary, lo que significaba que solo podía usarlo para las claves uint).

+0

El método de comprobación de BastardSaint que usa Contains() es algo (mucho) más inteligente que confiar en las excepciones. Esto dará un pico cada vez que se almacena la frecuencia de un nuevo número. –

+0

Pensando en ello ahora, tal vez hacer el control cada vez es una mejor manera de verificar la existencia. Supongo que depende de si esperas agregar muchos elementos muy similares (que yo soy) o si esperas un histograma con muchas entradas más. Mi corazonada era que sería más rápido en mi caso (?) –

+0

Cambié el ejemplo para usar la solución if-else. –

3

Puede utilizar 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); 
    }); 
0

Este código da representación gráfica de los valores de la matriz.

using System; 

// ... 
    static void Main(string[] args) 
    { 
     Console.ForegroundColor = ConsoleColor.Cyan; 
     int[] array = { 2, 2, 2 }; 
     PrintHistogram(array); 

     Console.ForegroundColor = ConsoleColor.Gray; 
     Console.Write("Press any key to quit . . . "); 
     Console.ReadKey(true); 
    } 

    static void PrintHistogram(int[] array) 
    { 
     int largest = 0; 

     for (int i = 0; i < array.Length; i++) 
      largest = Math.Max(largest, array[i]); 
     largest--; 

     // Bars 
     while (largest >= 0) 
     { 
      for (int i = 0; i < array.Length; i++) 
      { 
       if (array[i] > largest) 
        Console.Write("|\t"); 
       else 
        Console.Write("\t"); 
      } 

      largest--; 
      Console.WriteLine(); 
     } 

     Console.WriteLine(); 

     // Numbers 
     for (int i = 0; i < array.Length; i++) 
      Console.Write(array[i] + "\t"); 
     Console.WriteLine(); 
    }