如何根据百分比随机选择
本文关键字:随机 选择 百分比 何根 | 更新日期: 2023-09-27 18:24:07
我有一堆项目,它们超出了1-10
中大小的范围。
我想让物品的大小由百分比或物体达到该大小的可能性决定。。
例如:
大小的项目机会1
=50%
机会
大小的项目机会5
=20%
机会
大小的项目机会10
=5%
机会
当然,我知道我需要使用Random
生成器。
但只是想知道你们中的一些人会如何在C#中理解这一逻辑?
首先:提供的概率加起来不到100%:
50% + 20% + 5% = 75%
因此,您必须检查这些值。您可能想要生成这些每美分:
// Simplest, but not thread safe
private static Random s_Random = new Random();
...
int perCent = s_Random.Next(0, 100);
if (perCent < 50) // 0 .. 49
{
// return Item of size 1
}
else if (perCent < 50 + 20) // 50 .. 69
{
// return Item of size 5
}
else if (perCent < 50 + 20 + 5) // 70 .. 74
{
// return Item of size 10
}
...
使用我的方法。它简单易懂。我不计算0…1范围内的部分,我只使用"概率池"(听起来很酷,是吗?)我列出了我想从中选择的所有元素。每个元素都有自己的机会。将最常见元素的几率设置为100是有用的,因此大多数稀有元素将为60或50。
在圆形图中,您可以看到池中每个元素的重量
在这里你可以看到轮盘累积概率的实现
`
// Some c`lass or struct for represent items you want to roulette
public class Item
{
public string name; // not only string, any type of data
public int chance; // chance of getting this Item
}
public class ProportionalWheelSelection
{
public static Random rnd = new Random();
// Static method for using from anywhere. You can make its overload for accepting not only List, but arrays also:
// public static Item SelectItem (Item[] items)...
public static Item SelectItem(List<Item> items)
{
// Calculate the summa of all portions.
int poolSize = 0;
for (int i = 0; i < items.Count; i++)
{
poolSize += items[i].chance;
}
// Get a random integer from 0 to PoolSize.
int randomNumber = rnd.Next(0, poolSize) + 1;
// Detect the item, which corresponds to current random number.
int accumulatedProbability = 0;
for (int i = 0; i < items.Count; i++)
{
accumulatedProbability += items[i].chance;
if (randomNumber <= accumulatedProbability)
return items[i];
}
return null; // this code will never come while you use this programm right :)
}
}
// Example of using somewhere in your program:
static void Main(string[] args)
{
List<Item> items = new List<Item>();
items.Add(new Item() { name = "Anna", chance = 100});
items.Add(new Item() { name = "Alex", chance = 125});
items.Add(new Item() { name = "Dog", chance = 50});
items.Add(new Item() { name = "Cat", chance = 35});
Item newItem = ProportionalWheelSelection.SelectItem(items);
}
我是这样做的,也许对其他人有用。
public class Product
{
public int Id { get; set; }
public int Name { get; set; }
public int Percent { get; set; }
}
public class ChoiceItemModel
{
public int Id { get; set; }
public int Percent { get; set; }
public int Min { get; set; }
public int Max { get; set; }
}
public int ChoiceProduct(List<Product> products)
{
var chioiceItems = new List<ChoiceItemModel>();
var percent = 0;
foreach (var product in products.OrderByDescending(p => p.Percent).ToList())
{
chioiceItems.Add(new ChoiceItemModel()
{
Id = product.Id,
Percent = product.Percent,
Min = percent,
Max = product.Percent + percent
});
percent = product.Percent + percent; //max
}
var random = new Random();
var probability = random.Next(1, 100);
var found = chioiceItems.FirstOrDefault(p => probability > p.Min && probability <= p.Max);
if (found != null)
return found.Id;
}
我结束使用Oleksandr Martish的这一类,它针对泛型类型和Unity进行了修改,以防有人看到它的用处:)
public class ProportionalRandomSelector<T> {
private readonly Dictionary<T, int> percentageItemsDict;
public ProportionalRandomSelector() => percentageItemsDict = new();
public void AddPercentageItem(T item, int percentage) => percentageItemsDict.Add(item, percentage);
public T SelectItem() {
// Calculate the summa of all portions.
int poolSize = 0;
foreach (int i in percentageItemsDict.Values) {
poolSize += i;
}
// Get a random integer from 1 to PoolSize.
int randomNumber = Random.Range(1, poolSize);
// Detect the item, which corresponds to current random number.
int accumulatedProbability = 0;
foreach (KeyValuePair<T, int> pair in percentageItemsDict) {
accumulatedProbability += pair.Value;
if (randomNumber <= accumulatedProbability)
return pair.Key;
}
return default; // this code will never come while you use this programm right :)
}
}
//Example of use. You can use any type for the item too, and don't need an internal struct for the use.
public class Behaviour : MonoBehaviour {
ProportionalRandomSelector<string> randomSelector = new();
randomSelector.AddPercentageItem("Option1", 20);
randomSelector.AddPercentageItem("Option2", 30);
randomSelector.AddPercentageItem("Option3", 30);
randomSelector.AddPercentageItem("Option4", 15);
randomSelector.AddPercentageItem("Option5", 5);
string result = randomSelector.SelectItem();
}