2017-08-14 1 views
0

Ich versuche, ein großes Array von Zufallszahlen mit LINQ zu erstellen.System OutOfMemoryException beim Generieren von Array von Zufallszahlen

Ich möchte im Bereich 1.000.000 Zahlen erzeugen, die von 1 - 2147483647

Der folgende Code gut für kleine Zahlen funktioniert:

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

Aber erzeugt eine System.OutOfMemory Ausnahme, wenn ein großes Array zu erzeugen versuchen, .

Was ist der beste Weg, um das zu erreichen, was ich suche?

Edit: Danke für die Hilfe so weit, ich werde schreiben, warum ich das und meinen vollen Programmcode so mache:

In Bezug auf das Array, sollte es keine Duplikate enthält.

Ich schreibe ein Programm, das durch alle Zahlen iterieren, sie paaren und das Paar mit der geringsten Differenz zwischen ihnen zurückgeben wird. Oder geben Sie eine Liste aller Paare mit der kleinsten Differenz zurück, wenn es sich um Duplikate handelt.

Vollprogrammcode:

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; 
    } 

Edit 2:

Ich bin jetzt eine andere OutOfMemory Ausnahme an der Linie pairedDifferences.Add(new int[] { numbers[i], numbers[a], difference }); bekommen. Kennt jemand einen besseren Weg, dies zu tun? Entschuldigung, das ist das erste Mal, dass ich so etwas mache.

+4

Klingt wie AB Problem, können Sie teilen, warum Sie Array von Zufallszahlen so groß erstellen müssen? –

+2

"Ich möchte 1.000.000 Zahlen von 1 - 2147483647 generieren." Dubletten ausschließen? –

+0

Dieser Beitrag kann Ihnen helfen, die Grenzen eines Arrays zu verstehen: https://stackoverflow.com/questions/1391672/what-is-the-maximum-size-that-an-array-canhold –

Antwort

4

Ihr Code ist schlecht optimiert. In der Klasse Random können Sie einen Bereich angeben, aus dem Sie eine Zufallszahl auswählen. So müssen Sie nicht alles bestellen, was sehr teuer ist. Versuchen Sie, diese

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

Edit:

Es war bisher unklar, dass Duplikate sind nicht erlaubt. Wenn das der Fall ist, würde ich einen HashSet hinzufügen, um die bereits enthaltenen Zahlen zu verfolgen, wenn die Anzahl der erhaltenen Zufallszahlen erheblich kleiner ist als der Bereich, in dem sie sich befinden müssen, was hier der Fall ist.

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(); 

Auch this question für mehr Besuche auf Zufallszahlen ohne Duplikate zu erzeugen.

+0

Danke, Ihre Lösung hat funktioniert, aber jetzt bekomme ich eine weitere OutOfMemory-Ausnahme bei der Zeile 'paidedDifferences.Add (new int [] {numbers [i], numbers [a], difference}); Kennen Sie einen besseren Weg? Entschuldigung, das ist das erste Mal, dass ich so etwas mache. –

+0

An dieser Stelle versuchen Sie, '10^6 * 10^6' Elemente zu der Liste' pairedDifference' hinzuzufügen, was einfach unvernünftig ist. Versuchen Sie darüber nachzudenken, das Problem auf andere Weise zu lösen. – larsbe

-1

Es hat mit der OrderBy-Funktion zu tun. Das ist ein O (n) bei der Speichernutzung, das ist dein Problem.

O (n) ist eine lineare Speichernutzung. Mehr Input bedeutet also linear mehr Speicher.

0

Wenn Sie die Erzeugung von Zufallszahlen müssen ausgeglichen werden, können Sie den folgenden Code verwenden:

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(); 

, die für jede 2147483647/1000000 Zahlen zwischen 1 Zufallszahl erzeugen sollte.

Verwandte Themen