2009-05-29 3 views
8

Als Teil eines Prüfstands, den ich erstelle, suche ich nach einer einfachen Klasse zur Berechnung eines Histogramms ganzzahliger Werte (Anzahl der Iterationen für einen Algorithmus zur Lösung eines Problems) . Die Antwort sollte wie folgt aufgerufen werden:Einfache Histogrammgenerierung von Ganzzahldaten 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]); 
} 

ich ein bisschen googeln war überrascht hatte keine saubere Lösung auftauchen, aber vielleicht habe ich nicht für die richtigen Dinge suchen. Gibt es da draußen eine generische Lösung oder lohnt es sich, meine eigene zu rollen?

Antwort

12

könnten Sie verwenden 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); 
} 

Dies wird leeren Behälter auslassen, obwohl

+0

+1: Das sieht nach einem guten Start aus. Weil es passiert, bin ich nur an Bins interessiert, die Daten enthalten :-) –

6

Basierend auf BastardSaint Vorschlag kam ich mit einem ordentlichen und ziemlich allgemein Wrapper:

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

So jetzt kann ich tun:

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

Ich brauchte eine Weile, um herauszufinden, wie man es generisch machen kann (ich übertrumpfe einfach den SortedDictionary Konstruktor, was bedeutete, dass man ihn nur für uint Schlüssel verwenden konnte).

+0

Die Methode von BastardSaint, die Contains() zu verwenden, ist etwas (viel) klüger als sich auf Ausnahmen zu verlassen. Dies wird eine Spitze geben, jedes Mal, wenn die Frequenz einer neuen Nummer gespeichert wird. –

+0

Wenn Sie jetzt darüber nachdenken, ist es vielleicht besser, die Kontrolle jedes Mal zu überprüfen. Ich denke, es hängt davon ab, ob Sie erwarten, viele sehr ähnliche Elemente hinzuzufügen (was ich bin) oder ob Sie ein Histogramm mit viel mehr einzigartigen Inhalten erwarten. Meine Ahnung war, dass es in meinem Fall schneller wäre (?) –

+0

Das Beispiel wurde geändert, um die if-else-Lösung zu verwenden. –

3

können Sie Linq verwenden:

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

Dieser Code gibt grafische Darstellung der Feldwerte.

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