2016-06-17 24 views
17

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()?

+1

Możesz napisać własną metodę sprawdzania, czy wygenerowana liczba mieści się w wykluczonych zakresach iw tym przypadku ponownie ją wygenerować. –

+1

Dodałem losowy tag, aby wprowadzić to pytanie do wielu ekspertów liczb losowych na tej stronie, i dać mojej odpowiedzi pewną wiarygodność. – Bathsheba

Odpowiedz

12

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ć)

+1

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

5

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)]; 
+0

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

+0

@Programmer Unikaj także wyrażenia lambda? –

+0

Nie powiedziałbym tego.Chodzi mi o to, że jeśli on nazywał ten kod przez większość czasu, powinien tego unikać. – Programmer

10

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)]; 
+0

Po pierwsze, jest to statystycznie poprawne; Ufam, że przypisanie warunkowego testu do zmiennej zdefiniowanej po lewej stronie zadania jest dobrze zdefiniowane w C#! – Bathsheba

+0

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

0

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) 
+0

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

+0

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

+0

@Programmer, nie tylko w Unity, może zamrozić każdy program – Ignacio

-1

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); 
    } 
} 
1

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.