Come faccio a selezionare un valore casuale da un elenco?


170

Data un'enumerazione arbitraria in C #, come posso selezionare un valore casuale?

(Non ho trovato questa domanda basilare su SO. Pubblica la mia risposta tra un minuto come riferimento per chiunque, ma non esitate a pubblicare la vostra risposta.)

Risposte:


282
Array values = Enum.GetValues(typeof(Bar));
Random random = new Random();
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length));

40
Assicurati di non continuare a ricreare randomin un ciclo stretto, altrimenti continuerai a ottenere lo stesso valore.
ChrisF

1
Dovrebbe essere casuale. Avanti (valori.Lunghezza -1)?
uriDium,

7
@uriDium No, l'argomento specifica quale valore è il primo ad essere troppo grande per essere restituito (cioè massimo meno 1 )
mafu

value.Length - 1
Bojidar Stanchev

DarinDimitrov IMO il primo commento di @ChrisF dovrebbe essere una nota nella risposta con il merito a Chris.
Maytham

61

Utilizzare Enum.GetValues ​​per recuperare una matrice di tutti i valori. Quindi selezionare un oggetto array casuale.

static Random _R = new Random ();
static T RandomEnumValue<T> ()
{
    var v = Enum.GetValues (typeof (T));
    return (T) v.GetValue (_R.Next(v.Length));
}

Test:

for (int i = 0; i < 10; i++) {
    var value = RandomEnumValue<System.DayOfWeek> ();
    Console.WriteLine (value.ToString ());
}

->

Tuesday
Saturday
Wednesday
Monday
Friday
Saturday
Saturday
Saturday
Friday
Wednesday

5

Potresti semplicemente fare questo:

var rnd = new Random();
return (MyEnum) rnd.Next(Enum.GetNames(typeof(MyEnum)).Length);

Non è necessario archiviare array


GetNamesrestituisce un array.
Nathan Tuggy,

Volevo dire che non è necessario memorizzarlo. Mio cattivo
Breno Angelotti il

Se qualcuno lo fa in un ciclo, chiamerebbe GetNames ogni volta invece di memorizzarlo nella cache in un array. Questo rallenterebbe il loro codice, quindi non vedo quale sia il tuo contributo qui?
Bojidar Stanchev,

@BojidarStanchev IF , nel mio caso funziona alla grande, grazie Breno :)
Jaacko Torus

3

Ecco una versione alternativa come Extension Methodutilizzo LINQ.

using System;
using System.Linq;

public static class EnumExtensions
{
    public static Enum GetRandomEnumValue(this Type t)
    {
        return Enum.GetValues(t)          // get values from Type provided
            .OfType<Enum>()               // casts to Enum
            .OrderBy(e => Guid.NewGuid()) // mess with order of results
            .FirstOrDefault();            // take first item in result
    }
}

public static class Program
{
    public enum SomeEnum
    {
        One = 1,
        Two = 2,
        Three = 3,
        Four = 4
    }

    public static void Main()
    {
        for(int i=0; i < 10; i++)
        {
            Console.WriteLine(typeof(SomeEnum).GetRandomEnumValue());
        }
    }           
}

Due
Uno
Quattro
Quattro
Quattro
Tre
Due
Quattro
Uno
Tre


2

Chiama Enum.GetValues; questo restituisce un array che rappresenta tutti i possibili valori per il tuo enum. Scegli un oggetto casuale da questo array. Riporta l'oggetto al tipo di enum originale.


2

Ecco una funzione generica per questo. Mantenere la creazione di RNG al di fuori del codice ad alta frequenza.

public static Random RNG = new Random();

public static T RandomEnum<T>()
{  
    Type type = typeof(T);
    Array values = Enum.GetValues(type);
    lock(RNG)
    {
        object value= values.GetValue(RNG.Next(values.Length));
        return (T)Convert.ChangeType(value, type);
    }
}

Esempio di utilizzo:

System.Windows.Forms.Keys randomKey = RandomEnum<System.Windows.Forms.Keys>();

Avere un metodo statico che non è sicuro per i thread è piuttosto pericoloso.
CodesInChaos,

@CodesInChaos Hai ragione. Random.Next () non è thread-safe e inizierà a restituire zero quando si rompe. Ho aggiornato la mia risposta in base a queste informazioni.
Intero

1

Personalmente, sono un fan dei metodi di estensione, quindi userei qualcosa di simile (anche se non è un'estensione, sembra simile):

public enum Options {
    Zero,
    One,
    Two,
    Three,
    Four,
    Five
}

public static class RandomEnum {
    private static Random _Random = new Random(Environment.TickCount);

    public static T Of<T>() {
        if (!typeof(T).IsEnum)
            throw new InvalidOperationException("Must use Enum type");

        Array enumValues = Enum.GetValues(typeof(T));
        return (T)enumValues.GetValue(_Random.Next(enumValues.Length));
    }
}

[TestClass]
public class RandomTests {
    [TestMethod]
    public void TestMethod1() {
        Options option;
        for (int i = 0; i < 10; ++i) {
            option = RandomEnum.Of<Options>();
            Console.WriteLine(option);
        }
    }

}

1
A partire da C # 7.3 puoi limitare il tuo tipo generico ad essere un enum: public static T Of<T>() where T : Enum docs.microsoft.com/en-us/visualstudio/releasenotes/…
nitzel

0

Adattato come estensione di classe casuale:

public static class RandomExtensions
{   
    public static T NextEnum<T>(this Random random)
    {
        var values = Enum.GetValues(typeof(T));
        return (T)values.GetValue(random.Next(values.Length));
    }
}

Esempio di utilizzo:

var random = new Random();
var myEnumRandom = random.NextEnum<MyEnum>();

0

Puoi anche lanciare un valore casuale:

using System;

enum Test {
  Value1,
  Value2,
  Value3
}

class Program {
  public static void Main (string[] args) {
    var max = Enum.GetValues(typeof(Test)).Length;
    var value = (Test)new Random().Next(0, max - 1);
    Console.WriteLine(value);
  }
}

Ma dovresti usare un randomizzatore migliore come quello in questa mia biblioteca .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.