【问题标题】:make limitation for random class in c#在c#中限制随机类
【发布时间】:2011-03-27 21:18:51
【问题描述】:

我想限制 c# 中的随机类,比如从 2​​ 个范围内生成随机变量而不重复? 示例:

Xpoints[i] = random.Next(0, 25);
Ypoints[i] = random.Next(0, 12);

其中 25 我们 12 是图像尺寸,所以我需要此图像中的所有像素但随机?如果我使用此代码有任何建议,我没有得到一些像素和一些重复的像素

【问题讨论】:

    标签: c# random


    【解决方案1】:

    更新无需任何特定散列即可简化 [1]

    更新泛化为通用的SimpleShuffle扩展方法

            public static IEnumerable<T> SimpleShuffle<T>(this IEnumerable<T> sequence)
            {
                var rand = new Random();
                return sequence.Select(i => new {i, k=rand.Next()})
                    .OrderBy(p => p.k)
                    .Select(p => p.i);
            }
    

    我除了投反对票(大喊?对不起 :))Anx 的回答我认为最好也显示我的代码的样子:

    using System;
    using System.Linq;
    using System.Collections.Generic;
    
    namespace NS
    {
        static class Program
        {
            public static IEnumerable<T> SimpleShuffle<T>(this IEnumerable<T> sequence)
            {
                var rand = new Random();
                return sequence.Select(i => new {i, k=rand.Next()}).OrderBy(p => p.k).Select(p => p.i);
            }
    
            public static void Main(string[] args)
            {
                var pts = from x in Enumerable.Range(0, 24)
                    from y in Enumerable.Range(0, 11)
                    select new { x, y };
    
                foreach (var pt in pts.SimpleShuffle())
                    Console.WriteLine("{0},{1}", pt.x, pt.y);
            }
        }
    }
    

    我完全解决了我之前的问题,即如何通过意识到我们不需要散列来生成一个好的散列,除非:

    • 一个。源包含(逻辑)重复
    • 乙。我们需要它们具有相同的排序顺序
    • c。我们希望每次都有相同的“随机”排序顺序(确定性哈希)

    一个。和 b。在这种情况下是错误的,并且 c。甚至会成为一个问题(取决于 OP 的要求)。所以现在,没有任何附加条件,不再担心性能(甚至是非理性的担心),

    祝你好运!

    [1] 顺便说一句,这使整个事情更加灵活,因为我不再需要用字节 [] 来表示坐标;您现在可以随机播放您想要的任何结构。

    【讨论】:

    • 我试过你的答案更快,但你确定没有重复的同行吗?
    • @salamonti:是的,不能重复,因为我们只是按某个键对有限集合进行排序。 OrderBy 从不影响序列长度
    【解决方案2】:

    看看Fisher-Yates算法:

    http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

    它很容易实现,而且效果很好。

    它会打乱一组数字,然后您可以按顺序访问它们,以确保没有重复。

    【讨论】:

      【解决方案3】:

      您可能希望对索引列表(例如,X 轴值为 0..24 的 25 个元素)而不是随机使用随机播放算法。

      随机设计不保证没有重复值;重复的可能性很大。

      另请参阅:Optimal LINQ query to get a random sub collection - Shuffle(查找 Fisher-Yates-Durstenfeld 解决方案)

      【讨论】:

      • +1 用于链接正确的实现。我也喜欢 Jon Skeet 关于早产排序算法的说法。 Shuffle 实际上是按随机(加密)哈希排序...所以您也可以按密码哈希排序,然后使用普通排序
      【解决方案4】:

      我也相信,Random 不应该是可预测的,我们甚至不应该预测该值不会重复。

      但我认为有时可能需要随机获取非重复 int,因为我们需要维护状态,例如 Random 类的特定实例,返回所有值。

      这是我刚才想到的算法的一个快速而肮脏的小实现,我不确定它是否与 Fisher-Yates 解决方案相同。我刚刚编写了这个类,以便您可以使用它来代替 System.Random 类。

      所以它可以帮助您满足您的要求,根据您的需要使用下面的 NonRepeatingRandom 类...

      class NonRepeatingRandom : Random
      {
          private HashSet<int> _usedValues = new HashSet<int>();
          public NonRepeatingRandom()
          {
      
          }
          public NonRepeatingRandom(int seed):base(seed)
          {
      
          }
          public override int Next(int minValue, int maxValue)
          {
              int rndVal = base.Next(minValue, maxValue);
              if (_usedValues.Contains(rndVal))
              {
                  int oldRndVal = rndVal;
                  do
                  {
                      rndVal++;
                  } while (_usedValues.Contains(rndVal) && rndVal <= maxValue);
                  if (rndVal == maxValue + 1)
                  {
                      rndVal = oldRndVal;
                      do
                      {
                          rndVal--;
                      } while (_usedValues.Contains(rndVal) && rndVal >= minValue);
                      if (rndVal == minValue - 1)
                      {
                          throw new ApplicationException("Cannot get non repeating random for provided range.");
                      }
                  }
              }
              _usedValues.Add(rndVal);
              return rndVal;
          }
      }
      

      请不要只覆盖“Next”方法,而不是其他方法,如果您愿意,您也可以覆盖“Random”类的其他方法。

      附言。就在单击“发布您的答案”之前,我看到了 sehe 的答案,我喜欢他的整体想法,但是要散列 2 个字节,创建一个 16 字节的散列?还是我错过了什么?在我的代码中,我使用的是 HashSet,它使用 int 的 GetHashCode 方法实现,它只是 int 本身的值,因此没有散列开销。但我可能会错过一些要点,因为现在是印度凌晨 3:59 :)

      希望它可以帮助萨拉蒙蒂...

      【讨论】:

      • 是的:就像我说的,您可以使用像 (pt[1]*random1)^(pt[0]*random2) 这样的简单哈希,其中 random1 和 random2 足够大的静态随机整数。稍后我可能会编辑代码以包含真正的哈希(但有一些陷阱:需要考虑使用unchecked multiplcations 等。千万不要在午夜之后执行哈希实现 SERIOUS :)
      • 哦,顺便说一句,这个答案不是费雪-耶茨的任何想象。这只是 Anx 的解决方案,但已提取了查找。是的,哈希集可能在内部使用“哈希码”,但不能用于排序。 TRWTF 与您的方法是,您必须在内存中保留不断增长的整数列表。这不成比例。 (另外,Int32.GetHashCode() 根据定义返回 Int32 值...原文如此;我使用散列作为熵,您使用散列仅用于“快速查找”)
      • 感谢 sehe,澄清一下,我认为salamonti 需要在 Random 类中添加一个额外的功能,所以我只是扩展了 random 类以实现非重复性,我没有读到他需要所有的点,但在随机顺序。
      • 但是,关于内存大小,根据您的代码,对于 var pts,它将使用 528 个字节,对于我的代码,这取决于您为特定实例调用 Next Method 的次数,直到实例的范围,并且可能是相同的。
      • 关于“随机”的东西,如果它是关于图像的,那么你方法中的点顺序总是一样的,因为你实际上是在使用 orderby 对它们进行排序,所以 orderby 操作是为了一个巨大的图像(或积分)会更贵,如果有人随机需要这些积分,排序/排序根本不是一种选择。除非您使用哈希 + 加密随机数(再次随机)。
      【解决方案5】:

      随机数的全部意义在于你确实会得到重复。

      但是,如果您想确保在选择下一个数字之前不要从数组中删除最后选择的值。所以如果你有一个数字列表:

      index = random.Next(0, originallist.Length);
      radomisedList.Add(originalList[index]);
      originalList.RemoveAt(index);
      

      列表将随机排列,但不包含重复。

      【讨论】:

        【解决方案6】:

        您应该通过一个二维矩阵创建图像,而不是通过两个一维数组创建图像。每次获得新的随机坐标时,检查该像素是否已设置。如果是,则对该像素重复该过程。

        【讨论】:

        • 使用随机坐标时,最后几个像素可能非常“难以到达”,因为 X 和 Y 坐标都必须与剩余的像素匹配。因此,这似乎不是一个有效的解决方案。
        • 这取决于所需像素的百分比。 25×12=300,50%很容易达到,所以150像素不会有问题。
        • 引用问题:[...] 所以我需要所有像素 [...]
        • 不幸的是我需要 300 像素
        • 我忽略了引用的部分,因为它没有意义。如果应该设置所有像素,那么为什么不使用循环设置它们呢?
        猜你喜欢
        • 2012-11-19
        • 2013-10-05
        • 2013-07-19
        • 2014-10-12
        • 2014-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-31
        相关资源
        最近更新 更多