2010-02-28 2 views
7

Sono occupato in C# con la codifica di un array. Posso riempire con generatori casuali, ma ora è la mia domanda come faccio a fare questo, ma in modo che posso controllare se il valore è già nella matrice e in tal caso generare un valore nuovoGeneratore di numeri casuali in C# - valori univoci

Info extra:
valore di Max : 100
Numero di elementi: 100

IMPORTANTE LAVORO PLZ più avanti la mia idea

mia idea

public void FillArray(int[] A, int Range) 
{ 
    for (int I = 0; I < A.Length; I++) 
    { 
     A[I] = ValidNumber(T, I, Range); 
    } 
} /* Fill Array */ 

attuazione della selezione del tipo

public void SelectionSort(int[] A) 
{ 
    int K, X; 
    for (int I = 0; I < A.Length - 1; I++) 
    { 
     K = I; 
     X = A[K]; 
     for (int J = I + 1; J < A.Length; J++) 
     { 
      if (A[J] < X) 
      { 
       K = J; 
       X = A[K]; 
      } 
     } 
     A[K] = A[I]; 
     A[I] = X; 
    } 
} /* Selection sort */ 

Queste sono solo alcune idee ora voglio sapere come posso risolvere il problema in modo che io possa guardare con selection sort se c'è allread lì (FillArray), che è lo stesso, se così sostituirlo con un nuovo valore casuale. E così voglio creare un array casuale con ints - da 1 a 100 in un ordine casuale

+1

Gli odori come compiti a casa, in particolare con i commenti sotto i (validi, buoni) suggerimenti con uno scheletro che sembra essere parte del compito: "Inizia con questo codice" –

+0

sì, è davvero una parte dei compiti che non lo faccio mentire sul fatto che io sono solo bloccato in una parte e voglio così suggerimenti/feedback che non è male suppongo che – ShallowHeart

+1

corretto indentazione del codice e nomi di variabili migliori aiuterebbe le persone a capire il tuo codice e di conseguenza ti danno soluzioni migliori. – CesarGon

risposta

6

Quanto segue genererà un array con i numeri 1-100 in ordine casuale.

Random rnd = new Random(); 
    var randomNumbers = Enumerable.Range(1, 100).OrderBy(i => rnd.Next()).ToArray(); 
+0

Dovresti fornire un seme a 'Random()', ad es. 'new Random (DateTime.Now.Millisecond)' – AxelEckenberger

+8

Il costruttore vuoto su Random esegue questa operazione per impostazione predefinita (Enviroment.TickCount) –

+10

@Obalix: No, non si dovrebbe. Dovresti fornire un seme solo se vuoi essere in grado di fornire lo stesso ** seme di nuovo più tardi. In caso contrario, fare affidamento sul seeding predefinito. –

2

Ecco un'implementazione ingenuo:

int[] values = new int[100]; 
Random random = new Random(); 
for(int i = 0; i < values.Length; i++) 
{ 
    int v; 
    do 
    { 
     v = random.Next(100) + 1; 
    } while (Array.IndexOf(values, v) != -1) 
    values[i] = v; 
} 

ma sarebbe piuttosto inefficiente, soprattutto in prossimità della fine della matrice ...

Una soluzione migliore sarebbe quella di considerare che, dal momento che vuoi 100 valori distinti da 1 a 100 in ordine casuale, il tuo array conterrà tutti i valori possibili da 1 a 100. Quindi devi solo generare una sequenza di questi valori e "shuffle":

int[] values = Enumerable.Range(1, 100).ToArray(); 
Random random = new Random(); 
for(int i = values.Length - 1; i > 0; i--) 
{ 
    int j = random.Next(i + 1); 
    int tmp = values[i]; 
    values[i] = values[j]; 
    values[j] = tmp; 
} 

EDIT: un approccio migliore, che dovrebbe funzionare per i casi meno specifici:

T[] RandomCombinationWithNoRepeat<T>(IEnumerable<T> itemsToPickFrom, int numberOfItemsToPick) 
{ 
    // Copy original items to pick from, because we need to modify it 
    List<T> itemsCopy = new List<T>(itemsToPickFrom); 
    T[] array = new T[numberOfItemsToPick]; 
    Random random = new Random(); 
    for(int i = 0; i < numberOfItemsToPick; i++) 
    { 
     // Pick item and remove it from list 
     int index = random.Next(itemsCopy.Count); 
     array[i] = itemsCopy[index]; 
     itemsCopy.RemoveAt(index); 
    } 
    return array; 
} 

Nel tuo caso, si usa in quel modo:

int[] result = RandomCombinationWithNoRepeat(Enumerable.Range(1, 100), 100); 
+0

Ero più cercando un'oop soluzione \t è stato più pensare a un qualcosa di programmazione OOP come questo [code] public void FillArray (int [] A, int range) {for (int i = 0; i < A.Length; I ++ A [I] = ValidNumber (T, I, Range)} [/ code] Dopo questa piccola idea sono bloccato dopo tutto sto anche codificando molto rigorosamente tengo input, elaborazione e uscita in classi diverse – ShallowHeart

+0

Non penso che la 'Lista ' contenga una proprietà 'Lunghezza', probabilmente 'Conteggio'. –

+0

@PhilippeLavoie, sì, hai ragione ... Ho risolto, grazie! –

5

Dalla tua descrizione Prendo che è necessario un array di 100 numeri interi con valori da 1 a 100 e nessun numero duplicato. Se i numeri sono numeri interi non è necessario generare numeri casuali, poiché tutti i numeri possibili sono nell'array. Pertanto, solo l'ordine oi numeri possono essere randomizzati.

Utilizzando l'approccio di Linq e Jesper Palm - con Thomas Levesque la seguente affermazione ti fornirà l'array di cui hai bisogno.

Random rnd = new Random(); 
var randomNumbers = Enumerable.Range(1, 100) 
           .Select(x => new { val = x, order = rnd.Next() }) 
           .OrderBy(i => i.order) 
           .Select(x => x.val) 
           .ToArray(); 

Il metodo è anche abbastanza veloce, sicuramente più efficiente di qualsiasi operazione di confronto.

Per spiegare quanto sopra per il manifesto originale, si veda il commento qui sotto:

  • Enumerable.Range(1, 100) crea una serie di numeri interi a partire da 1 e che termina a 100.
  • .Select(x => new { val = x, order = rnd.Next() }) crea un nuovo oggetto temporaneo contenente il valore e la posizione dell'ordine, che è determinata da un numero casuale.
  • .OrderBy(i => i.order) ordina gli oggetti temporanei in base alla posizione dell'ordine.
  • .Select(x => x.val) seleziona il valore dell'oggetto temporaneo, convertendolo di nuovo in int.
  • .ToArray() trasforma di nuovo tutto in un array.

La sintassi utilizzata è LINQ, disponibile in .NET 3.5. Con le versioni precedenti dovresti implementarlo tu stesso, il che è molto più complicato e molto più lungo.

seguito il commento di Eric: Se incasinare è requried si può fare il codice come segue

var list = myInputList; 
var result = list.Select(x => new { val = x, order = rnd.Next() }) 
       .OrderBy(i => i.order) 
       .Select(x => x.val) 
       .ToArray(); 
+0

thnx tutti voi per la risposta, ma potete per favore guardare la mia idea Btw ho w aggiungi il codice in quella scatola grigia? Sì, sono un principiante qui intorno. Anche io voglio sottolineare che sono un principiante di C# ho solo qualche mese di esperienza. E io non so nemmeno cosa ci sia qualche cosa che tu presenti qui, anche me come enumerable.range che deve essere la gamma. Ordine di deve essere stato ordinato. Ma immagino che il codice ordinerà tutti i numeri nell'array che cosa non è il concetto che non voglio raggiungere. Voglio raggiungere solo un array casuale con 100 elementi con numeri compresi tra 1 e 100 in un ordine casuale. – ShallowHeart

+0

@ShallowHeart, penso che ti manchi il punto. Il codice prende i numeri da 1 a 100 e quindi li "ordina" in un ordine * determinato a caso *. Questa è una tecnica standard per mischiare. –

+0

@Obalix La tua risposta mi ha salvato molto del mio tempo. Puoi dirmi cosa devo fare se voglio ottenere una serie di dire 30 numeri in cui la gamma massima sta cambiando? Quello che ho fatto è stato generare l'array di numeri casuali per l'intervallo completo utilizzando il frammento e memorizzare i primi 30 elementi richiesti nel mio array. Come posso modificare questo codice per incorporare anche quello per ridurre il tempo di loop. – Jerin

0

da quello che ho capito. Hai bisogno di una collezione di numeri interi con numeri casuali. Presumo che l'uso di int array o List of int non abbia importanza. Ecco un semplice approccio completo che hai descritto.
using System; using System.Collections.Generic; using System.Text;

namespace FillRandom { class Program { static void Main(string[] args) { int minValue = 1; int maxValue = 100; //create a list of int with capacity set as 100 List array = new List(100);

 FillArray(array, minValue, maxValue, array.Capacity); 

     //print out all values in the array 
     foreach (int i in array) 
     { 
      Console.WriteLine(i); 
     } 
    } 

    private static void FillArray(List<int> array, int minValue, int maxValue, int capacity) 
    { 
     int count = 0; 
     while (array.Count != capacity - 1) 
     { 
      Random rnd = new Random(); 
      int value = rnd.Next(minValue, maxValue); 
      if (!array.Contains(value)) 
      { 
       array.Add(value); 
      } 
      count++; 
     } 
     //print out the number of times the looping occurs 
     Console.WriteLine("count: "+count); 
    }   
} 

}

È possibile creare un progetto di console e fare un tentativo.

+0

Eric ha perfettamente ragione che questa è davvero una cattiva idea e ho provato a stamparlo usando "count". ;) Comunque, una scoperta interessante è che in realtà rende più difficile riempire l'array se un nuovo oggetto Random è stato creato ogni volta (circa 100k a 200k loop) ma usando lo stesso oggetto, ci sono voluti circa 500 volte. – Blithe

30

come faccio a fare questo, ma in modo che posso controllare se il valore è già nella matrice e in tal caso generare un valore nuovo

Lei non farlo, mai, perché che è una pessima idea.

Per illustrare il motivo per cui è una pessima idea, prendere in considerazione un'altra versione dello stesso problema: ordinare un milione di numeri in un ordine casuale dal seguente processo:

  1. scegliere un numero da uno a un milione.
  2. Verificare se è già presente nell'elenco.
  3. In caso affermativo, tornare al passaggio 1
  4. In caso contrario, aggiungere il numero all'elenco.
  5. L'elenco contiene un milione di articoli? Se sì, hai finito. In caso contrario, tornare al passaggio 1.

Chiaramente questo funziona. È una buona idea? Supponiamo che tu abbia quasi finito. L'elenco contiene 999999 elementi. L'unico elemento mancante è 857313. Che cosa fai? Scegli un numero casuale, diciamo, 12. Ora controlli gli articoli 999999 nell'elenco per vedere se uno di essi è 12. 12 potrebbe essere stato uno dei primi numeri che hai scelto, quindi potrebbe essere veloce trovarlo. O potrebbe essere uno degli ultimi, quindi ci vorrà molto tempo. In media ci vorranno 500000 assegni per vedere se 12 sono nella lista. Ed è, dal momento che c'è un solo numero mancante dalla lista.

12 non ha funzionato. Torna all'inizio. Scegli un altro numero casuale, ad esempio 53259. È presente nell'elenco? Altri mezzo milione di assegni.

Continuate così fino a quando non generate 857313, che avviene ogni milione di tentativi.

Quindi, in media, mettere l'ultimo elemento nell'elenco richiede 500000 x 1000000 = cinquecento miliardi di confronti. Potrebbe volerci molto di più. Potrebbero essere necessari diversi trilioni di confronti. O potresti essere fortunato e ci vuole uno. Ma in media, mezzo trilione di confronti.

Questo è un terribile modo per produrre un ordine casuale di un elenco.

Esistono due modi per effettuare un ordinamento casuale di un elenco.

(1) Creare un dispositivo in grado di ordinare un elenco in base alla funzione di ordinamento. Fornire un ordine stabile a basato su un seme casuale.

Si noti che è necessario non produrre un ordine casuale eseguendo un metodo che restituisce risultati casuali quando viene richiesto "è maggiore di B?" Questo è un ordine instabile; molti algoritmi di ordinamento sono previsti su un ordinamento di ordinamento stabile e andranno in loop infiniti o hanno altri comportamenti errati quando viene fornito un ordinamento di ordinamento instabile.

Questo algoritmo è O (n lg n) e ha la bella proprietà che è molto facile scrivere su parti standard, come indicano altre risposte. È anche estremamente veloce per piccoli elenchi in implementazioni tipiche.

(2) Scegliere un elemento per indice da un elenco di origini casuali, rimuovere dall'elenco di origini mentre si va e inserirlo nell'elenco di destinazioni.

Quest'ultimo è noto come Knuth Shuffle o Fischer-Yates Shuffle ed è un algoritmo molto veloce. Puoi farlo "sul posto", trasformando un array esistente in ordine casuale o creando un nuovo elenco. Ha anche la bella proprietà che puoi "pagare per giocare", mischiando la "cima" della lista quando ne hai bisogno. Se hai un milione di oggetti da mescolare ma hai bisogno solo dei primi cento, puoi calcolare l'ordinamento per i primi cento e chiamarlo buono.

+1

Sento che il secondo consiglio è eccezionale. –

+0

ottima risposta, è un ottimo approccio dato che questa domanda si riferisce a un compito a casa e non stai solo dicendo di copiare questo e il gioco è fatto +1 –

+0

Sto usando il secondo metodo al momento ed è meraviglioso. Ottima risposta, +1. – Abluescarab