【问题标题】:System OutOfMemoryException when generating array of random numbers生成随机数数组时出现 System OutOfMemoryException
【发布时间】:2018-01-22 04:41:46
【问题描述】:

我正在尝试使用 LINQ 创建大量随机数。

我想生成 1,000,000 个从 1 到 2147483647 的数字。

以下代码适用于小数字:

    int[] numbers = Enumerable.Range(1, 2147483647)
                              .OrderBy(x => rnd.Next())
                              .Take(num)
                              .ToArray();

但在尝试生成大型数组时会产生 System.OutOfMemory 异常。

实现我所寻找的最佳方式是什么?

编辑: 感谢到目前为止的帮助,我会写下我这样做的原因以及我的完整程序代码:

关于数组,它不应包含重复项。

我正在编写一个程序,它将遍历所有数字,将它们配对并返回它们之间差异最小的对。或者如果它们是重复的,则返回具有最小差异的所有对的列表。

完整程序代码:

    static void Main(string[] args)
    {
        // Keep running until close
        while (true)
        {
            Console.WriteLine("Write a number:");
            Console.WriteLine(ClosestNumbers(Convert.ToInt32(Console.ReadLine())));
        }
    }

    public static string ClosestNumbers(int num)
    {
        string returnString = "\n\nRandom numbers:\n";
        returnString += "---------------------------------------\n";

        Random rnd = new Random();

        // Generate array of {num} random numbers ranging from 1 to 2147483647.
        int[] numbers = Enumerable.Range(1, 1000000)
                                  .OrderBy(x => rnd.Next(1, 2147483647))
                                  .Take(num)
                                  .ToArray();

        //returnString += string.Join(",", numbers.ToArray()) + "\n";

        // Array format: {num1, num2, difference}
        List<int[]> pairedDifferences = new List<int[]>();

        int endPoint = numbers.Length;
        int difference = 0;

        for (int i = 0; i < endPoint - 1; i++)
        {

            for (int a = i + 1; a < endPoint; a++)
            {

                if (numbers[i] > numbers[a])
                {
                    difference = numbers[i] - numbers[a];
                }
                else
                {
                    difference = numbers[a] - numbers[i];
                }

                pairedDifferences.Add(new int[] { numbers[i], numbers[a], difference });

            }

        }

        int minDiff = pairedDifferences.Min(x => x[2]);

        List<int[]> minDiffsList = pairedDifferences.Where(x => x[2] == minDiff).ToList();

        returnString += "---------------------------------------\n\n\n";
        returnString += "Smallest difference(s) found between:\n\n";            

        foreach (int[] minDiffItem in minDiffsList)
        {
            // minDiffItem[0];      // first num
            // minDiffItem[1];      // second num
            // minDiffItem[2];      // difference

            returnString += $"{minDiffItem[0]} and {minDiffItem[1]}, with a difference of {minDiffItem[2]}.\n";
        }

        returnString += "\n\n\n===================================================================\n";
        returnString += "===================================================================\n\n\n";

        return returnString;
    }

编辑 2:

我现在在 pairedDifferences.Add(new int[] { numbers[i], numbers[a], difference }); 线。有谁知道更好的方法来做到这一点?抱歉,这是我第一次做这样的事情。

【问题讨论】:

  • 听起来像 AB 问题,你能分享一下为什么需要创建这么大的随机数数组吗?
  • "我想生成 1,000,000 个从 1 到 2147483647 的数字。"排除重复项?
  • 这篇文章可以帮助你理解数组的限制:stackoverflow.com/questions/1391672/…
  • 是,不包括重复项。我正在编写一个程序,它将遍历所有数字,将它们配对并返回它们之间差异最小的对。或者如果它们是重复的,则返回具有最小差异的所有对的列表。
  • @BenMurphy 你需要随机数在数组中均衡吗?即例如 [1..2147483647 / 1000000] 范围内只有 1 个随机数,或者此范围内可能有超过 1 个随机数?

标签: c# .net arrays linq memory


【解决方案1】:

如果需要随机数生成平衡,可以使用如下代码:

const int rangeCount = 1_000_000;
int rangeSize = 2_147_483_647 / rangeCount;

int[] numbers = Enumerable.Range(1, rangeCount)
                          .Select(rangeIndex => 
                           {
                             int from = ((rangeIndex - 1) * rangeSize) + 1;
                             int to = from + rangeSize;

                             return rnd.Next(from, to);
                           })
                          .ToArray();

应该为每个 2147483647 / 1000000 个数字范围产生 1 个随机数。

【讨论】:

    【解决方案2】:

    您的代码优化不佳。 Random 类允许您指定从中获取随机数的范围。这样您就不需要订购所有东西,这非常昂贵。试试这个

    int[] numbers = Enumerable.Range(1, 1000000)
                              .Select(i => rnd.Next(1, 2147483647))
                              .ToArray();
    

    编辑:

    以前不清楚是否允许重复。如果是这种情况,我会添加一个HashSet 来跟踪已经包含的数字,如果获得的随机数的数量远远小于它们必须在的范围,即这里的情况。

    var memory = new HashSet<int>();
    int[] numbers = Enumerable.Range(1, 1000000)
                              .Select(i =>
                              {
                                   int number;
                                   do
                                   {
                                        number = rnd.Next(1, 2147483647);
                                   } while (memory.Contains(number));
                                   return number;
                              })
                              .ToArray();
    

    还可以查看this question,了解更多关于生成无重复随机数的信息。

    【讨论】:

    • 谢谢,您的解决方案有效,但现在我在 pairedDifferences.Add(new int[] { numbers[i], numbers[a], difference }); 行遇到了另一个 OutOfMemory 异常。你知道更好的方法吗?抱歉,这是我第一次做这样的事情。
    • 此时你正在尝试将10^6*10^6 元素添加到pairedDifference 列表中,这简直是不合理的。尝试以不同的方式解决问题。
    【解决方案3】:

    它与 OrderBy 函数有关。这是内存使用量的 O(n),这是你的问题。

    O(n) 构成线性内存使用量。所以更多的输入意味着线性更多的内存。

    【讨论】:

      猜你喜欢
      • 2014-09-30
      • 1970-01-01
      • 2021-05-15
      • 2020-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多