Jeśli używasz Random.Range()
do generowania wartości, czy istnieje sposób na wykluczenie niektórych wartości z zakresu (na przykład: wybierz liczbę od 1 do 20, ale nie od 6 do 8)?Wyklucz wartości z Random.Range()?
Odpowiedz
Najlepszym sposobem, aby to zrobić, to użyć ulubionego generator wygenerować liczbę całkowitą n
pomiędzy 1 a 17 następnie przekształcać stosując
if (n > 5){
n += 3;
}
Jeśli próbki pomiędzy 1 a 20 następnie odrzucić wartości można przedstawić nieprawidłowości statystyczne . (Na przykład, wariancja będzie zbyt wysoka, jeśli generator liczb losowych jest liniowy przystający jeden. Spróbować i zobaczyć)
Czy możesz wytłumaczyć (lub powiązać z wyjaśnieniem), dlaczego wariancja byłaby zbyt wysoka, jeśli próbujesz i odrzucasz? (Bo wydaje mi się to zaskakujące!) – davidbak
Tak, prosta obsługa where
statment w LINQ
var list = Enumerable.Range(1, 20).Where(a => a < 6 || a > 8).ToArray();
Inny sposób witout LINQ
public IEnumerable RangeBetween()
{
foreach (var i in Enumerable.Range(1, 20))
{
if (i < 6 || i > 8)
{
yield return i;
}
}
}
EDYCJA: Teraz widzę, nie jest to surowe pytanie C#. Wpływa na Unity
i Random
. Ale dla pełnej odpowiedzi I sugest użyć kodu powyżej Enumerable.Range
i następnego użycia tego do generowania numeru:
list[Random.Next(list.Length)];
To jest dla silnika gry. Jeśli możesz uniknąć linq, unikaj tego. Przydziela pamięć, a niektóre funkcje nie działają w systemie iOS. – Programmer
@Programmer Unikaj także wyrażenia lambda? –
Nie powiedziałbym tego.Chodzi mi o to, że jeśli on nazywał ten kod przez większość czasu, powinien tego unikać. – Programmer
Więc rzeczywiście chcesz 17
(20 - 3) różne wartości
[1..5] U [9..20]
i można implement coś takiego:
// Simplest, not thread-safe
private static Random random = new Random();
...
int r = (r = random.Next(1, 17)) > 5
? r + 3
: r;
W ogólnym (i skomplikowanym) przypadku proponuję wygenerować tablicę wszystkich możliwych wartości, a następnie wziąć element od niego:
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)];
Po pierwsze, jest to statystycznie poprawne; Ufam, że przypisanie warunkowego testu do zmiennej zdefiniowanej po lewej stronie zadania jest dobrze zdefiniowane w C#! – Bathsheba
Unity3D zapewnia losową klasę i większość użytkowników polega na tym. Ponadto Linq nie jest tak polecany w Unity z przyczyn wewnętrznych (FullAOT na iOS), który sprawia, że niektóre jego funkcje nie zawsze działają. – Everts
To będzie wybrać inną liczbę losową jeśli r jest w przedziale 6-8 włącznie.
int r = 0;
do
{
r = Random.Next(20);
} while (r >= 6 && r <= 8)
Myślę, że za pomocą tej metody istnieje szansa (naprawdę mała, ale wciąż), że program wchodzi w nieskończoną pętlę ... jeśli zawsze dostajesz numer od 6 do 8. – Ignacio
Mam ochotę komentować ten. To świetny sposób na zamrożenie gry. @Ignacio Masz rację. Zdarzyło mi się to wcześniej. Nie podczas pętli podczas generowania liczby losowej w Unity. – Programmer
@Programmer, nie tylko w Unity, może zamrozić każdy program – Ignacio
Zamierzam rzucić moje 2 centy na ten temat. Oto pełna klasa pokazująca metodę, która generuje losową liczbę wykluczającą wybrane liczby i sposób jej użycia.
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);
}
}
Innym sposobem jest, aby szereg ważnych wartości zwracanej, a następnie losowo wybrać jeden:
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: Ups! Właśnie zauważyłem, że to było dla Unity3D, więc ten przykład może nie być odpowiedni. Działa jednak ze standardową klasą Random
.
Możesz napisać własną metodę sprawdzania, czy wygenerowana liczba mieści się w wykluczonych zakresach iw tym przypadku ponownie ją wygenerować. –
Dodałem losowy tag, aby wprowadzić to pytanie do wielu ekspertów liczb losowych na tej stronie, i dać mojej odpowiedzi pewną wiarygodność. – Bathsheba