2016-06-17 42 views
17

Se si utilizza Random.Range() per generare valori, esiste un modo per escludere alcuni valori all'interno dell'intervallo (ad esempio: selezionare un numero compreso tra 1 e 20, ma non tra 6 e 8)?Escludi valori da Random.Range()?

+1

È possibile scrivere il proprio metodo per verificare se il numero generato rientra negli intervalli esclusi e in questo caso rigenerarlo. –

+1

Ho aggiunto il tag casuale per introdurre questa domanda ai molti esperti di numeri casuali su questo sito e per dare alla mia risposta una certa credibilità. – Bathsheba

risposta

12

Il modo migliore per farlo è quello di utilizzare il generatore preferito per generare un intero n compreso tra 1 e 17 quindi trasformare utilizzando

if (n > 5){ 
    n += 3; 
} 

Se campione tra 1 e 20 poi scarta i valori è possibile introdurre anomalie statistiche . (Ad esempio, la varianza sarà troppo alto se il generatore di numeri casuali è un lineare congruenziale uno:. Provare e vedere)

+1

Puoi spiegare (o collegare a una spiegazione) perché la varianza sarebbe troppo alta se campionassi e scartasti? (Perché mi sembra sorprendente!) – davidbak

5

Sì, è semplice utilizzo where statment in LINQ

var list = Enumerable.Range(1, 20).Where(a => a < 6 || a > 8).ToArray(); 

Altro modo Witout LINQ

 public IEnumerable RangeBetween() 
     { 
      foreach (var i in Enumerable.Range(1, 20)) 
      { 
       if (i < 6 || i > 8) 
       { 
        yield return i; 
       } 
      } 
     } 

MODIFICA: Ora vedo che non è una domanda C# rigorosa. Colpisce Unity e Random. Ma per risposta completa io suggerisco si utilizza il codice di cui sopra con Enumerable.Range e successivo uso questo per generare il numero:

list[Random.Next(list.Length)]; 
+0

Questo è per il motore di gioco. Se riesci a evitare linq, evitalo. Alloca la memoria e alcune funzioni non funzionano in iOS. – Programmer

+0

@Programmer Evita anche l'espressione lambda? –

+0

Non lo direi.Voglio dire, se chiama quel codice per la maggior parte del tempo, dovrebbe evitarlo. – Programmer

10

Così si vuole realmente 17 (20 - 3) valori diversi

[1..5] U [9..20] 

e si può implementare qualcosa di simile:

// Simplest, not thread-safe 
    private static Random random = new Random(); 

    ... 

    int r = (r = random.Next(1, 17)) > 5 
    ? r + 3 
    : r; 

In caso generale (e complicato) suggerisco generare un array di tutti i valori possibili e poi prendere 0.123.l'elemento da esso:

int[] values = Enumerable 
    .Range(1, 100) // [1..100], but 
    .Where(item => item % 2 == 1) // Odd values only 
    .Where(item => !(item >= 5 && item <= 15)) // with [5..15] range excluded 
    //TODO: Add as many conditions via .Where(item => ...) as you want 
    .ToArray(); 

    ... 

    int r = values[random.Next(values.Length)]; 
+0

Più uno, questo è statisticamente corretto; Sono fiducioso che l'assegnazione del test condizionale a una variabile che hai definito a sinistra del compito è ben definita in C#! – Bathsheba

+0

Unity3D fornisce una classe Random e la maggior parte degli utenti si affida a quella. Inoltre, Linq non è raccomandato in Unity per motivi interni (FullAOT su iOS), il che rende alcune delle sue funzionalità non sempre funzionanti. – Everts

0

Ciò scegliere un numero casuale diverso se r è nel range 6-8 compreso.

int r = 0; 
do 
{ 
    r = Random.Next(20); 
} while (r >= 6 && r <= 8) 
+0

Penso che usando questo metodo ci sia una possibilità (molto piccola, ma ancora) che il programma entri in un ciclo infinito ... se ottieni sempre un numero tra 6 e 8. – Ignacio

+0

Mi sento di commentare questo. Questo è un ottimo modo per congelare il tuo gioco. @ Ignacio Hai ragione. Questo mi è già successo. Nessun ciclo while durante la generazione di un numero casuale in Unity. – Programmer

+0

@Programmer, non solo in Unity, può bloccare qualsiasi programma – Ignacio

-1

Ho intenzione di buttare i miei 2 centesimi sull'argomento. Ecco una lezione completa che mostra un metodo che genera un numero casuale che esclude i numeri di tua scelta e come usarlo.

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

public class test2 : MonoBehaviour { 

    System.Random rand; 
    int[] excludelist; 
    void Start() 
    { 
     rand = new System.Random(); 
     excludelist = new int[] { 5,9,3}; 
     for(int i = 0; i<20;i++) 
     { 
      Debug.Log(MakeMeNumber(excludelist)); 
     } 

    } 
    private int MakeMeNumber(params int[] excludeList) 
    { 
     var excluding = new HashSet<int>(excludeList); 
     var range = Enumerable.Range(1, 20).Where(i => !excluding.Contains(i)); 


     int index = rand.Next(0, 20 - excluding.Count); 
     return range.ElementAt(index); 
    } 
} 
1

Un altro modo è quello di rendere una matrice dei valori di ritorno validi e quindi selezionare casualmente uno:

void Main() 
{ 
    var rng = new Random(); 
    var validValues = Enumerable.Range(1, 20).Except(new int[] {6, 7, 8}).ToArray(); 

    for (int i = 0; i < 25; i++) 
    { 
     Console.Write(validValues[rng.Next(0, validValues.Length)]); 
     Console.Write(" "); 
    } 
} 

EDIT: Oops! Ho appena notato che questo era per Unity3D, quindi questo esempio potrebbe non essere appropriato. Funziona usando la classe standard Random, però.