2013-01-23 25 views
15

Ho cercato per un po 'e ho faticato a trovarlo, sto provando a generare diversi numeri casuali e univoci è C#. Sto utilizzando System.Random, e sto usando un seme datetime.now.ticks:Generazione di valori casuali e univoci C#

public Random a = new Random(DateTime.Now.Ticks.GetHashCode()); 
private void NewNumber() 
    { 
    MyNumber = a.Next(0, 10); 
    } 

sto chiamando NewNumber() regolarmente, ma il problema è spesso ricevo numeri ripetuti. Alcune persone hanno suggerito perché stavo dichiarando il random ogni volta che l'ho fatto, non avrebbe prodotto un numero casuale, quindi ho messo la dichiarazione fuori dalla mia funzione. Eventuali suggerimenti o modi migliori rispetto all'utilizzo di System.Random? Grazie

+2

http://csharpindepth.com/Articles/Chapter12/Random.aspx – Habib

+0

Fintanto che si sta creando solo l'oggetto a caso una volta, non si dovrebbe avere un problema. Se vuoi che i numeri siano unici (non hai ancora avuto quel numero), dovrai aggiungere altro che usare Random – RoneRackal

+1

Stai cercando "permutazione di numeri 1..10" invece di "numero casuale" intervallo 1..10 "? (Dare in modo definitivo 10 numeri univoci in sequenza casuale) –

risposta

14

Sto chiamando NewNumber() regolarmente, ma il problema è che ottengo spesso numeri ripetuti .

Random.Next non specifica il numero per essere univoco. Anche il tuo range va da 0 a 10 e probabilmente avrai dei valori duplicati. Può essere possibile impostare un elenco di int e inserire numeri casuali nell'elenco dopo aver controllato se non contiene il duplicato. Qualcosa di simile:

public Random a = new Random(); // replace from new Random(DateTime.Now.Ticks.GetHashCode()); 
           // Since similar code is done in default constructor internally 
public List<int> randomList = new List<int>(); 
int MyNumber = 0; 
private void NewNumber() 
{ 
    MyNumber = a.Next(0, 10); 
    if (!randomList.Contains(MyNumber)) 
     randomList.Add(MyNumber); 
} 
+2

+1. Anche per qualcosa di più di 10 liste sarebbe una scelta sbagliata, HashSet sarebbe meglio. E non c'è bisogno di inizializzare in modo casuale in questo modo - codice simile fatto nel costruttore predefinito in ogni caso ... –

+0

Grazie cumuli che hanno funzionato perfettamente! –

13

Si potrebbe provare a mischiare una serie di possibili int se l'intervallo è solo 0 a 9. Ciò si aggiunge il vantaggio di evitare eventuali conflitti nella generazione di numeri.

var nums = Enumerable.Range(0, 10).ToArray(); 
var rnd = new Random(); 

// Shuffle the array 
for (int i = 0;i < nums.Length;++i) 
{ 
    int randomIndex = rnd.Next(nums.Length); 
    int temp = nums[randomIndex]; 
    nums[randomIndex] = nums[i]; 
    nums[i] = temp; 
} 

// Now your array is randomized and you can simply print them in order 
for (int i = 0;i < nums.Length;++i) 
    Console.WriteLine(nums[i]); 
+0

L'ho appena provato e ha funzionato bene! grazie mille! –

+0

Attenzione! Questa è un'implementazione scorretta dello shuffle! Pubblicherò una corretta implementazione in un attimo. –

+0

(troppo tardi per modificare il mio commento sopra ora). Si prega di vedere il mio post qui sotto per una corretta implementazione, nonché un link ad alcune discussioni su di esso. –

1

A seconda di cosa siete realmente dopo si può fare qualcosa di simile:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace SO14473321 
{ 
    class Program 
    { 
     static void Main() 
     { 
      UniqueRandom u = new UniqueRandom(Enumerable.Range(1,10)); 
      for (int i = 0; i < 10; i++) 
      { 
       Console.Write("{0} ",u.Next()); 
      } 
     } 
    } 

    class UniqueRandom 
    { 
     private readonly List<int> _currentList; 
     private readonly Random _random = new Random(); 

     public UniqueRandom(IEnumerable<int> seed) 
     { 
      _currentList = new List<int>(seed); 
     } 

     public int Next() 
     { 
      if (_currentList.Count == 0) 
      { 
       throw new ApplicationException("No more numbers"); 
      } 

      int i = _random.Next(_currentList.Count); 
      int result = _currentList[i]; 
      _currentList.RemoveAt(i); 
      return result; 
     } 
    } 
} 
8

sto postando una corretta implementazione di un algoritmo casuale, dal momento che l'altro postato qui non produce un'ordinaria mescolanza.

Come per gli altri termini di risposta, per un numero limitato di valori da assegnare in modo casuale, è sufficiente riempire un array con tali valori, mescolare l'array e quindi utilizzare comunque molti dei valori desiderati.

Quanto segue è un'implementazione dello Fisher-Yates Shuffle (noto anche come Knuth Shuffle). (Leggi la sezione "errori di implementazione" di quel link (cerca "sempre selezionando j dall'intero intervallo di indici di array validi su ogni iterazione") per vedere qualche discussione su cosa c'è di sbagliato nell'altra implementazione pubblicata qui.)

using System; 
using System.Collections.Generic; 

namespace ConsoleApplication2 
{ 
    static class Program 
    { 
     static void Main(string[] args) 
     { 
      Shuffler shuffler = new Shuffler(); 
      List<int> list = new List<int>{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 
      shuffler.Shuffle(list); 

      foreach (int value in list) 
      { 
       Console.WriteLine(value); 
      } 
     } 
    } 

    /// <summary>Used to shuffle collections.</summary> 

    public class Shuffler 
    { 
     /// <summary>Creates the shuffler with a <see cref="MersenneTwister"/> as the random number generator.</summary> 

     public Shuffler() 
     { 
      _rng = new Random(); 
     } 

     /// <summary>Shuffles the specified array.</summary> 
     /// <typeparam name="T">The type of the array elements.</typeparam> 
     /// <param name="array">The array to shuffle.</param> 

     public void Shuffle<T>(IList<T> array) 
     { 
      for (int n = array.Count; n > 1;) 
      { 
       int k = _rng.Next(n); 
       --n; 
       T temp = array[n]; 
       array[n] = array[k]; 
       array[k] = temp; 
      } 
     } 

     private System.Random _rng; 
    } 
} 
+0

@downvoters: hai indagato il problema con l'altro casuale shuffle? La risposta in questione è quella sotto la risposta accettata. Sta usando un algoritmo shuffle errato. Vedi anche i miei commenti per quella risposta. –

+0

Perché è meglio dell'altro? (apar da quello che hai reso generico) –

+0

@ Mitulátbáti Quale risposta intendi con "l'altro"? Se intendi "la risposta accettata", allora questa è migliore perché ha complessità "O (N)" mentre la risposta accettata ha complessità "O (N^2)". –

-1

Si potrebbe anche usare un dataTable la memorizzazione di ogni valore casuale, quindi è sufficiente eseguire il metodo casuale mentre! = valori nel DataColumn

8

NOTA, io non consiglio questo :). Ecco un "oneliner" così:

//This code generates numbers between 1 - 100 and then takes 10 of them. 
var result = Enumerable.Range(1,101).OrderBy(g => Guid.NewGuid()).Take(10).ToArray(); 
+0

Come dove sei andato qui. Ma perché no: 'Enumerable.Range (0, 9) .OrderBy (g => rand.NextDouble()). ToList()' quindi ottieni l'intervallo come da domanda. – SDK

+1

Se si desiderano due numeri univoci compresi tra 1 e 10.000.000, ciò sarà estremamente lento. – Rob

-3

Prova questo:

private void NewNumber() 
    { 
    Random a = new Random(Guid.newGuid().GetHashCode()); 
    MyNumber = a.Next(0, 10); 
    } 

Alcune Explnations:

Guid: base on here: Rappresenta un identificatore univoco globale (GUID)

Guid.newGuid() produce un identificatore univoco come "936DA01F-9ABD-4d9d-80C7-02AF85C822A8"

e sarà unica in tutto l'universo base on here

codice hash here producono un numero intero univoco dal nostro identificatore univoco

così Guid.newGuid().GetHashCode() ci dà un numero unico e la classe casuale produrrà numeri reali casuali buttare questo

+3

Per favore aggiungi una spiegazione. – OhBeWise

+0

@Rob Sì, questo produrrà un valore univoco, lo hai provato? – AliTheOne

+3

No, non lo farò. Nessun motivo per cui due chiamate successive non produrranno lo stesso valore. Reseeding per ogni campione è un classico modello anti. –

0

E qui la mia versione di trovare N numeri univoci casuali usando HashSet. Sembra piuttosto semplice, poiché HashSet può contenere solo elementi diversi. È interessante - sarebbe più veloce usare List o Shuffler?

using System; 
using System.Collections.Generic; 

namespace ConsoleApplication1 
{ 
    class RnDHash 
    { 
     static void Main() 
     { 
      HashSet<int> rndIndexes = new HashSet<int>(); 
      Random rng = new Random(); 
      int maxNumber; 
      Console.Write("Please input Max number: "); 
      maxNumber = int.Parse(Console.ReadLine()); 
      int iter = 0; 
      while (rndIndexes.Count != maxNumber) 
      { 
       int index = rng.Next(maxNumber); 
       rndIndexes.Add(index); 
       iter++; 
      } 
      Console.WriteLine("Random numbers were found in {0} iterations: ", iter); 
      foreach (int num in rndIndexes) 
      { 
       Console.WriteLine(num); 
      } 
      Console.ReadKey(); 
     } 
    } 
} 
-2

È possibile utilizzare le funzioni casuali di base di C#

Random ran = new Random(); 
int randomno = ran.Next(0,100); 

ora è possibile utilizzare il valore nel randomno in tutto quello che vuoi, ma tenere a mente che questo genererà un numero casuale compreso tra 0 e 100 Solo e puoi estenderlo a qualsiasi figura.

+0

Ciò non garantisce alcun valore esclusivo. –

0

Verificare questo metodo pronto per l'uso: Assegnare un intervallo & numero di numeri che si desidera ottenere.

public static int[] getUniqueRandomArray(int min, int max, int count) { 
    int[] result = new int[count]; 
    List<int> numbersInOrder = new List<int>(); 
    for (var x = min; x < max; x++) { 
     numbersInOrder.Add(x); 
    } 
    for (var x = 0; x < count; x++) { 
     var randomIndex = Random.Range(0, numbersInOrder.Count); 
     result[x] = numbersInOrder[randomIndex]; 
     numbersInOrder.RemoveAt(randomIndex); 
    } 

    return result; 
} 
Problemi correlati