Pregunta

Como parte de un banco de pruebas que estoy construyendo, estoy buscando una clase simple para calcular un histograma de valores enteros (número de iteraciones tomadas de un algoritmo para resolver un problema). La respuesta debería llamarse algo como esto:

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 busco las cosas correctas. ¿Hay una solución genérica por ahí o se trata de la pena rodar mi propia?

¿Fue útil?

Solución

Se puede usar 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

Otros consejos

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

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

Así que ahora puedo hacer:

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 para encontrar la manera de hacer que los medicamentos genéricos (para empezar yo sólo hizo caso omiso de la constructora SortedDictionary lo que significaba que sólo se podía utilizar para llaves uint).

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);
    });
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top