从概率列表中选择随机元素

时间:2017-10-13 17:26:19

标签: c# list random probability

我有一个包含四个项目(A,B,C,D)的列表。每个项目都有可能被选中。比方说,A有74%的机会被选中,B 15%,C 7%和D 4%。

我想创建一个根据概率随机选择项目的函数。

请帮忙吗?

4 个答案:

答案 0 :(得分:3)

为您的商品定义一个类:

class Items<T>
{
    public double Probability { get; set; }
    public T Item { get; set; }
}

然后初始化

var initial = new List<Items<string>>
{
    new Items<string> {Probability = 74 / 100.0, Item = "A"},
    new Items<string> {Probability = 15 / 100.0, Item = "B"},
    new Items<string> {Probability = 7 / 100.0, Item = "C"},
    new Items<string> {Probability = 4 / 100.0, Item = "D"},
};

然后你需要转换它来汇总从0到1的概率之和

var converted = new List<Items<string>>(initial.Count);
var sum = 0.0;
foreach (var item in initial.Take(initial.Count - 1))
{
    sum += item.Probability;
    converted.Add(new Items<string> {Probability = sum, Item = item.Item});
}
converted.Add(new Items<string> {Probability = 1.0, Item = initial.Last().Item});

现在您可以从converted集合中选择一个关于概率的项目:

var rnd = new Random();
while (true)
{
    var probability = rnd.NextDouble();
    var selected = converted.SkipWhile(i => i.Probability < probability).First();
    Console.WriteLine($"Selected item = {selected.Item}");
}

注意:我的实施具有O(n)复杂度。您可以使用二进制搜索对其进行优化(因为converted集合中的值已排序)

答案 1 :(得分:1)

我很抱歉这样回答这个问题 - 我有点认为它是一种&#34; Euler.Net&#34;拼图,以及一种玩弄Generics的方法。

无论如何,我在这里:

public class WeightedItem<T>
{
    private T value;
    private int weight;
    private int cumulativeSum;
    private static Random rndInst = new Random();

    public WeightedItem(T value, int weight)
    {
        this.value = value;
        this.weight = weight;
    }

    public static T Choose(List<WeightedItem<T>> items)
    {
        int cumulSum = 0;
        int cnt = items.Count();

        for (int slot = 0; slot < cnt; slot++)
        {
            cumulSum += items[slot].weight;
            items[slot].cumulativeSum = cumulSum;
        }

        double divSpot = rndInst.NextDouble() * cumulSum;
        WeightedItem<T> chosen =  items.FirstOrDefault(i => i.cumulativeSum >= divSpot);
        if (chosen == null) throw new Exception("No item chosen - there seems to be a problem with the probability distribution.");
        return chosen.value;
    }
}

用法:

        WeightedItem<string> alice = new WeightedItem<string>("alice", 1);
        WeightedItem<string> bob = new WeightedItem<string>("bob", 1);
        WeightedItem<string> charlie = new WeightedItem<string>("charlie", 1);
        WeightedItem<string> diana = new WeightedItem<string>("diana", 4);
        WeightedItem<string> elaine = new WeightedItem<string>("elaine", 1);

        List<WeightedItem<string>> myList = new List<WeightedItem<string>> { alice, bob, charlie, diana, elaine };
        string chosen = WeightedItem<string>.Choose(myList);

答案 2 :(得分:0)

using System;

public class Test{
    private static String[] values = {"A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","B","B","B","B","B","B","B","B","B","B","B","B","B","B","B","C","C","C","C","C","C","C","D","D","D","D",};

    private static Random PRNG = new Random();

    public static void Main(){
        Console.WriteLine( values[PRNG.Next(values.Length)] );
    }
}

答案 3 :(得分:-4)

您最好的选择是从1-100中选择一个数字,看看它是否属于该类别。

伪代码 -

x = randnum(1-100)
if 1 <= x < 50:
     #50%, etc.