Construire une list non séquentielle de nombres (à partir d'une large gamme)

J'ai besoin de créer une list non séquentielle de nombres qui rentrent dans une plage. Par exemple, j'ai besoin de générer une list de nombres de 1 à 1 million et de m'assurer que les nombres ne sont pas dans un ordre séquentiel, qu'ils sont complètement mélangés. Je suppose que ma première question est la suivante: y a-t-il de bons algorithms qui pourraient aider et la meilleure façon d'implémenter cela?

Je ne suis pas sûr de la meilleure façon de l'implémenter, soit via une application de console ac # qui crachera les nombres dans un file XML ou dans une database qui cracera les nombres dans une table ou un set de tables, mais c'est vraiment secondaire à l'élaboration effective de la meilleure façon de "mélanger" l'set des nombres.

Des conseils, les gars?

Rob

Comment "non séquentiel" le voulez-vous?

Vous pouvez facilement générer une list de nombres randoms à partir d'une plage avec la class Random:

Random rnd1 = new Random(); List<int> largeList = new List<int>(); for (int i = 0, i < largeNumber, i++) { largeList.Add(rnd1.Next(1, 1000001); } 

Modifier pour append

Certes l'algorithm de Durstenfeld (version moderne du shuffle de Fisher-Yates apparemment) est beaucoup plus rapide:

 var fisherYates = new List<int>(upperBound); for (int i = 0; i < upperBound; i++) { fisherYates.Add(i); } int n = upperBound; while (n > 1) { n--; int k = rnd.Next(n + 1); int temp = fisherYates[k]; fisherYates[k] = fisherYates[n]; fisherYates[n] = temp; } 

Pour la gamme de 1 à 10000, une force brute "find un nombre random que je n'ai pas encore utilisé" prend environ 4-5 secondes, alors que cela prend environ 0,001.

Props à Greg Hewgill pour les liens.

Tout d'abord, si aucun des nombres n'est dans l'ordre séquentiel alors chaque nombre dans la séquence doit être inférieur à son prédécesseur. Une séquence qui a cette propriété est sortingée du plus grand au plus petit! Clairement, ce n'est pas ce que vous voulez. (Ou peut-être vous ne voulez simplement pas une sous-séquence de la forme 5, 6, 7? Mais 6, 8, 20 serait OK?)

Pour répondre correctement à votre question, nous avons besoin de plus d'informations sur l'espace problème. Choses que je voudrais savoir:

1) La taille de la plage est-elle égale, supérieure ou inférieure à la taille de la séquence? Autrement dit, allez-vous requestr dix numéros entre 1 et 10, cinq numéros entre 1 et 10 ou cinquante numéros entre 1 et 10?

2) Est-il acceptable que la séquence contienne des duplicates? (Si le nombre d'éléments de la séquence est supérieur à la plage, alors oui.)

3) Quel est le caractère random utilisé? La plupart des générateurs de nombres randoms ne sont que pseudo-randoms; un attaquant intelligent peut déduire le prochain nombre "random" en connaissant les précédents. Si par exemple vous générez une série de cinq maps sur un package de 52 pour faire une main de poker, vous voulez vraiment fort caractère random; vous ne voulez pas que les joueurs puissent déduire ce que leurs adversaires ont entre les mains.

Je comprends, que vous voulez get un tableau random de 1mio lenth avec tous les nombres de 1 à 1mio. Pas de duplicates, n'est-ce pas?

Vous devriez build un tableau avec vos nombres allant de 1 à 1mio. Puis commencez à mélanger. Mais il peut arriver (c'est le vrai hasard) que deux nombres encore plus nombreux soient séquentiels.

Jetez un oeil ici

Voici une fonction C # pour vous aider à démarrer:

 public IEnumerable<int> GetRandomSequence(int max) { var r = new Random(); while (true) { yield return r.GetNext(max); } } 

appelez-le comme ceci pour get un million de numéros rangés 0-9999999:

 var numbers = GetRandomSequence(9999999).Take(1000000); 

Pour ce qui est du sorting, ou si vous ne voulez pas autoriser les répétitions, regardez Enumerable.GetRange() (qui vous donnera une séquence ordonnée consécutive ) et utilisez un algorithm de shuffle Fisher-Yates (ou Knuth) (que vous pouvez find tous sur le lieu).

"complètement mélangé" est un terme très mal compris. Une astuce utilisée par les experts de la fraude lors de l'examen de données "randoms" est de surveiller les cas où il n'y a pas de valeurs dupliquées (comme 3743 *** 88 *** 123, car dans une séquence vraiment random les chances de ne pas avoir une telle paire est très faible … Qu'est-ce que vous voulez dire exactement par "complètement mélangé"? Si vous voulez dire une séquence random de numbers, alors utilisez simplement la class Random dans le CLR pour générer des nombres randoms entre 0 et 1M … autant que vous avez besoin …

Eh bien, vous pourriez aller avec quelque chose comme ça (en supposant que vous voulez chaque nombre exactement une fois):

 DECLARE @intFrom int DECLARE @intTo int DECLARE @tblList table (_id uniqueidentifier, _number int) SET @intFrom = 0 SET @intTo = 1000000 WHILE (@intFrom < @intTo) BEGIN INSERT INTO @tblList SELECT NewID(), @intFrom SET @intFrom = @intFrom + 1 END SELECT * FROM @tblList ORDER BY _id 

DISCLAIMER: Je n'ai pas testé cela, car je n'ai pas de SQL Server à ma disposition pour le moment.

Cela peut vous apporter ce dont vous avez besoin:

1) Remplir une list de nombres dans l'ordre. Si votre plage est 1 – x, cela ressemblera à ceci: [1, 2, 4, 5, 6, 7, 8, 9, …, x]

2) Boucle sur la list x fois, en choisissant chaque fois un nombre random entre 0 et la longueur de votre list – 1.

3) Utilisez ce numéro choisi pour sélectionner l'élément correspondant de votre list et ajoutez ce numéro à votre list de sortie.

4) Supprimez l'élément que vous venez de sélectionner dans votre list. Rincez, répétez.

Cela fonctionnera pour n'importe quelle plage de nombres, pas seulement pour les lists commençant par 1 ou 0. Le pseudo-code ressemble à ceci:

 nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] shuffled_nums = [] for i in range(0, len(nums)): random_index = rand(0,len(nums)) shuffled_nums.add(nums[random_index]) del(nums[random_index])