So I have this class called ProbabilisticEnumerator, it accepts a map of elements and integer-based weights. See the following example:
var myProbabilityTable = new Dictionary<char, uint> {
{ 'A', 1 }, // 14.29%
{ 'B', 2 }, // 28.57%
{ 'C', 4 }, // 57.14%
};
I am trying to figure out an efficient way to invert this so that one can pass float-based values (which might be more natural to some). Here is an example of what I might mean:
var myProbabilityTable = new Dictionary<char, float> {
{ 'A', 0.1429f }, // 1
{ 'B', 0.2857f }, // 2
{ 'C', 0.5714f }, // 4
};
So far the best I have been able to come up with is an approach that takes a minimum of two passes; the first to get the total weight and a second to create the new dictionary. Is there a better way that one could accomplish this? Am I missing any edge cases that might cause things to "blow up?"
My Attempt:
class Program {
static void Main(string[] args) {
var floatWeights= new Dictionary<string, float> {
{ "A", 25.0f },
{ "B", 60.0f },
{ "C", 15.0f },
};
var integerWeights = ConvertFloatWeightsToInteger(floatWeights);
foreach(var item in integerWeights) {
Console.WriteLine(item);
}
}
static Dictionary<T, int> ConvertFloatWeightsToInteger<T>(Dictionary<T, float> elementWeights) {
var totalWeight = 0f;
foreach (var weight in elementWeights.Values) {
if (float.IsNegative(weight) || float.IsSubnormal(weight)) {
throw new ArgumentOutOfRangeException(actualValue: weight, message: "weight must be a positive normal floating-point number", paramName: nameof(weight));
}
totalWeight += weight;
}
return elementWeights.ToDictionary(
keySelector: k => k.Key,
elementSelector: e => ((int)((e.Value / totalWeight) * 1000000000))
);
}
}