Этот файл находится в Mathematica, но его легко скопировать на другой язык, я использую его в своих играх и он может обрабатывать десятичные веса:
weights = {0.5,1,2}; // The weights
weights = N@weights/Total@weights // Normalize weights so that the list's sum is always 1.
min = 0; // First min value should be 0
max = weights[[1]]; // First max value should be the first element of the newly created weights list. Note that in Mathematica the first element has index of 1, not 0.
random = RandomReal[]; // Generate a random float from 0 to 1;
For[i = 1, i <= Length@weights, i++,
If[random >= min && random < max,
Print["Chosen index number: " <> ToString@i]
];
min += weights[[i]];
If[i == Length@weights,
max = 1,
max += weights[[i + 1]]
]
]
(Теперь я говорю с индексом первого элемента списка равен 0) . Идея заключается в том, что с нормализованным списком весов существует вероятность того, что вес [n] вернет index n , поэтому расстояния между min и max на шаге n должны быть весами [n] . Общее расстояние от минимального min (которое мы считаем равным 0) , а максимальное максимальное - суммой весов списка .
Хорошая вещь заключается в том, что вы не добавляете ни один массив или гнездо для циклов, и это значительно увеличивает время выполнения.
Вот код на C #, не требующий нормализации веса и удаление некоторого кода:
int WeightedRandom(List<float> weights) {
float total = 0f;
foreach (float weight in weights) {
total += weight;
}
float max = weights [0],
random = Random.Range(0f, total);
for (int index = 0; index < weights.Count; index++) {
if (random < max) {
return index;
} else if (index == weights.Count - 1) {
return weights.Count-1;
}
max += weights[index+1];
}
return -1;
}