【问题标题】:Container that returns random value based on a chance/wight基于机会/重量返回随机值的容器
【发布时间】:2013-02-14 12:46:39
【问题描述】:

如何最好地制作一个 Container 类,该类根据在添加元素期间输入的权重返回随机值?

理想情况下它应该像这样使用:

var randomContainer = new RandomContainer<IThing>();
randomContainer.Add(new CoolThing(), 80);
randomContainer.Add(new AwesomeThing(), 20);
IThing thing = randomContainer.Get();

所以事物有 80% 的机会成为 CoolThing 和 20% 的机会成为 AwesomeThing。

但算法不应该要求权重加起来为 100,所以这也应该是可能的:

var randomContainer = new RandomContainer<IThing>();
randomContainer.Add(new CoolThing(), 398);
randomContainer.Add(new AwesomeThing(), 485);
randomContainer.Add(new SpecialThing(), 1);
IThing thing = randomContainer.Get();

任何想法如何实现这样的算法?类应该有哪些成员/属性?实现ICollection有意义吗?

【问题讨论】:

    标签: c# algorithm random containers


    【解决方案1】:

    那个算法应该很简单:

    在 1 和所有权重之和之间选择一个随机值。该值将指示要返回的对象。

    第二个示例的示例:

    • 值 1 到 398 将返回 CoolThing
    • 值 399 到 883 (= 398 + 485) 将返回 AwesomeThing
    • 值 884 将返回 SpecialThing

    【讨论】:

      【解决方案2】:

      我认为 Daniel Hilgarth 的回答是正确的,因为他让我走上了正确的道路。

      对于任何想要示例实现的人:

      public class RandomContainer<T> 
      {
          private Random _random = new Random();
      
          private Dictionary<T, int> _objects = new Dictionary<T, int>();
          private int _weightSum;
      
          public RandomContainer()
          {           
          }
      
          public void Add(T obj, int weight)
          {          
              _objects.Add(obj, weight);
              _weightSum += weight;
          }
      
          public T Get()
          {
              int sumExtra = 0;
              int rand = _random.Next(0, _weightSum);
              foreach(var kvp in _objects)
              {
                  if(rand < kvp.Value + sumExtra)
                      return kvp.Key;
                  sumExtra += kvp.Value;
              }
              return default(T); // This shouldn't be reached
          }
      }
      

      它不包含很多标准方法,但关键在于 Get() 函数,其余的应该很容易实现。

      【讨论】:

      • 这个容器可以容纳大量物品吗?因为你当前的实现是 O(n)。
      • 请注意,Random.Next 有一个独占上限。它必须是_random.Next(1, _weightSum + 1)
      • @DanielHilgarth 感谢您的提示,修复了上限。容器可能最多只能容纳 20 个对象,所以 O(n) 应该没问题。
      • @DanielHilgarth 实际上_random.Next(1, _weightSum) 是对的,因为我使用的是rand &lt; kvp.Value + sumExtra,但我可能也应该将1 更改为0。是的,现在看起来不错
      • 如果您将相同的物品(类型)添加两次但重量不同怎么办?这对计算有何影响?
      猜你喜欢
      • 2021-12-26
      • 2019-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多