【问题标题】:Get a random list of integer array in C#在 C# 中获取整数数组的随机列表
【发布时间】:2019-04-23 18:41:00
【问题描述】:
public static List<int> GetRandom()
{
    Random rnd = new Random();
    List<int> list = new List<int>();

    while (list.Count <= 26)
    {
        int randomNumber = rnd.Next(1, 26);

        if (!list.Contains(randomNumber))
        {
            list.Add(randomNumber);
        }
    }

    return list;
}

这是一个代码,我试图获取一个随机整数列表(从 1 到 26),但这并没有返回我想要的结果。这里我想要一个没有任何重复的随机 int 数组。

【问题讨论】:

  • 您的rnd 应该为应用程序的运行创建一次,而不是在每次调用该方法时创建。
  • 您不希望它们只是随机的。您也希望它们独一无二。
  • @TheodorZoulias - 是的,先生,我已经得到了答案
  • @Nishan 你有答案,但你的方法有点低效。因为每次迭代你将有更高的概率生成一个已经存在的数字,所以你的概率将从 1/n、2/n...n-1/n... 你会浪费一些时间循环直到你真正生成唯一编号...

标签: c#


【解决方案1】:

那是因为您试图获取 1-25 之间的数字,所以您的代码将永远不会离开循环。你应该像这样调用随机数

int randomNumber = rnd.Next(1, 27);

【讨论】:

  • 为了展开,Next() 的第一个参数是inclusive,但第二个参数是exclusive。这意味着第一个参数应该是您所需数字范围内可能的最小数字,第二个参数应该是最大可能的数字 + 1
  • 认为这也会导致无限循环,因为尼山正在做while(list.Count &lt;= 26)
  • 什么都没发生
  • @Nishan 作为测试,您可以将while 循环条件更改为while(list.Count &lt; 26),而不是&lt;=。或者,您可以保持原样,并将Next 方法的第二个参数(如Paulo 所述)增加到28。否则你仍然处于无限循环中。
  • @Sam 你是对的。它现在正在工作。感谢您在这里发表评论
【解决方案2】:

实际上,您希望随机化整数范围。你可以使用System.Linq

Random rnd = new Random();
Enumerable.Range(1, 27).OrderBy(_ => rnd.Next())

.NET Fiddle


我什至使用 BenchmarkDotNet 测量和比较了两种解决方案,尽管我很确定,只是作为确认。已经测量了两种情况,一种是原始的,另一种是有 1000 个随机元素的。如果增加元素的数量,您可能会看到性能下降(这是合乎逻辑的,因为随着元素数量的增加,您发生碰撞的可能性会更高)。

BenchmarkDotNet=v0.11.5, OS=Windows 7 SP1 (6.1.7601.0)
Intel Core i7-6700 CPU 3.40GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
Frequency=3328320 Hz, Resolution=300.4519 ns, Timer=TSC
[Host]     : .NET Framework 4.6.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2650.0
DefaultJob : .NET Framework 4.6.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2650.0

n=26

| Method |     Mean |     Error |    StdDev | Rank |
|------- |---------:|----------:|----------:|-----:|
|   Your | 4.463 us | 0.0882 us | 0.1936 us |    2 |
|   Mine | 2.597 us | 0.0235 us | 0.0220 us |    1 |

n=1000

| Method |       Mean |       Error |      StdDev | Rank |
|------- |-----------:|------------:|------------:|-----:|
|   Your | 6,095.8 us | 119.4976 us | 122.7152 us |    2 |
|   Mine |   148.1 us |   0.6086 us |   0.5692 us |    1 |

【讨论】:

  • 您能告诉我哪一种方法在性能方面是最好的吗?为什么?
  • @Nishan 性能下降是因为在Random.Next 期间你可能会发生碰撞所以你浪费了一个循环,我的建议你没有碰撞所以领先时间是OrderBy 复杂度n*平均登录。查看更新...
  • 知道了。感谢您的宝贵时间
【解决方案3】:

作为替代方案,您可以使用 MathNet.Numerics 库:

PM> 安装包 MathNet.Numerics

public static List<int> GetRandom()
{
    var arr = Combinatorics.GeneratePermutation(25);
    return new List<int>(arr);
}

您可能需要加 1,因为它会生成从零开始的数组。

这里是相关的documentation

生成随机排列,不重复,通过生成 索引编号 0 到 N-1 并随机打乱它们。使用实现 费雪-耶茨洗牌。

【讨论】:

    【解决方案4】:

    Random 作为静态变量保留在方法之外可确保您始终获得不同的数字列表,即使您快速连续多次调用该方法。

    private static Random StaticRandom = new Random();
    
    public static List<int> GetUniqueRandomNumbers_From_1_to_26()
    {
        return Enumerable.Range(1, 26).OrderBy(_ => StaticRandom.Next()).ToList();
    }
    

    使用示例:

    Console.WriteLine(String.Join(", ", GetUniqueRandomNumbers_From_1_to_26()));
    

    输出:

    26, 19, 22, 24, 16, 20, 5, 1, 8, 6, 10, 14, 13, 18, 15, 12, 25, 2, 4, 9, 21, 7, 23, 11, 3, 17
    

    【讨论】:

      猜你喜欢
      • 2013-07-06
      • 2018-11-06
      • 2015-01-27
      • 2023-03-11
      • 2021-07-03
      • 2013-07-28
      • 2015-09-07
      • 2011-08-11
      • 1970-01-01
      相关资源
      最近更新 更多