2009-05-29 17 views
8

Come parte di un banco di prova che sto costruendo, sto cercando una classe semplice per calcolare un istogramma di valori interi (numero di iterazioni eseguite per un algoritmo per risolvere un problema) . La risposta dovrebbe essere chiamato qualcosa come questo:Generazione di istogrammi semplici di numeri interi in 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]); 
} 

Sono rimasto sorpreso un po 'di googling non si presentò una soluzione pulita, ma forse io non cercare le cose giuste. Esiste una soluzione generica là fuori o vale la pena far girare il mio?

risposta

12

Si potrebbe utilizzare 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); 
} 

Questo lascerà fuori bidoni vuoti, anche se

+0

+1: Sembra un buon inizio. Come accade, mi interessano solo i bin che contengono i dati :-) –

6

Basato su suggerimento di BastardSaint mi si avvicinò con un involucro ordinata e abbastanza generica:

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

Così ora posso fare:

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

Mi ci è voluto un po 'per capire come renderlo generico (per cominciare ho solo annullato il costruttore SortedDictionary, il che significava che potevi usarlo solo per le chiavi uint).

+0

Il metodo di verifica di BastardSaint che utilizza Contains() è un po '(molto) più saggio di fare affidamento sulle eccezioni. Questo darà un picco ogni volta che viene memorizzata la frequenza di un nuovo numero. –

+0

Pensandoci ora, forse fare il controllo ogni volta è un modo migliore per verificare l'esistenza. Immagino che dipenda se ti aspetti di aggiungere molti oggetti molto simili (che io sono) o se ti stai aspettando un istogramma con molti altri titoli unici. La mia impressione era che sarebbe stato più veloce nel mio caso (?) –

+0

Modificato l'esempio per usare la soluzione if-else. –

3

È possibile utilizzare 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

Questo codice dà rappresentazione grafica dei valori di matrice.

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(); 
    } 
Problemi correlati