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()?
risposta
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)
Puoi spiegare (o collegare a una spiegazione) perché la varianza sarebbe troppo alta se campionassi e scartasti? (Perché mi sembra sorprendente!) – davidbak
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)];
Questo è per il motore di gioco. Se riesci a evitare linq, evitalo. Alloca la memoria e alcune funzioni non funzionano in iOS. – Programmer
@Programmer Evita anche l'espressione lambda? –
Non lo direi.Voglio dire, se chiama quel codice per la maggior parte del tempo, dovrebbe evitarlo. – Programmer
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)];
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
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
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)
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
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
@Programmer, non solo in Unity, può bloccare qualsiasi programma – Ignacio
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);
}
}
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ò.
È possibile scrivere il proprio metodo per verificare se il numero generato rientra negli intervalli esclusi e in questo caso rigenerarlo. –
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