¿Cómo selecciono un valor aleatorio de una enumeración?

171

Dada una enumeración arbitraria en C #, ¿cómo selecciono un valor aleatorio?

(No encontré esta pregunta muy básica sobre SO. Publicaré mi respuesta en un minuto como referencia para cualquiera, pero no dude en publicar su propia respuesta).

mafu
fuente

Respuestas:

282
Array values = Enum.GetValues(typeof(Bar));
Random random = new Random();
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length));
Darin Dimitrov
fuente
40
Sin randomembargo, asegúrese de no seguir recreando en un ciclo cerrado; de lo contrario, seguirá obteniendo el mismo valor.
ChrisF
1
¿Debería ser aleatorio. Siguiente (valores. Longitud -1)?
uriDium
77
@uriDium No, el argumento especifica qué valor es el primero en ser demasiado grande para ser devuelto (es decir, máximo menos 1 )
mafu
valores.Longitud - 1
Bojidar Stanchev
DarinDimitrov IMO el primer comentario de @ChrisF debería ser una nota dentro de la respuesta con crédito a Chris.
maytham-ɯɐɥʇʎɐɯ
62

Use Enum.GetValues ​​para recuperar una matriz de todos los valores. Luego seleccione un elemento de matriz aleatorio.

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

Prueba:

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
mafu
fuente
5

Podrías hacer esto:

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

No es necesario almacenar matrices

Breno Angelotti
fuente
GetNamesdevuelve una matriz
Nathan Tuggy
Quise decir que no necesitas almacenarlo. My bad
Breno Angelotti
Si alguien está haciendo esto en un bucle, llamaría a GetNames cada vez en lugar de almacenarlo en caché en una matriz. Esto ralentizaría su código, así que no veo cuál es su contribución aquí.
Bojidar Stanchev
@BojidarStanchev IF , en mi caso esto funciona de maravilla, gracias Breno :)
Jaacko Torus
4

Aquí hay una versión alternativa como un Extension Methoduso 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());
        }
    }           
}

Dos
Uno
Cuatro
Cuatro
Cuatro
Tres
Dos
Cuatro
Uno
Tres

Aaron Hudon
fuente
2

Llamada Enum.GetValues; esto devuelve una matriz que representa todos los valores posibles para su enumeración. Elija un elemento aleatorio de esta matriz. Devuelve ese elemento al tipo de enumeración original.

Tim Robinson
fuente
2

Aquí hay una función genérica para ello. Mantenga la creación de RNG fuera del código de alta frecuencia.

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

Ejemplo de uso:

System.Windows.Forms.Keys randomKey = RandomEnum<System.Windows.Forms.Keys>();
WHOL
fuente
Tener un método estático que no sea seguro para subprocesos es bastante peligroso.
CodesInChaos
@CodesInChaos Tienes razón. Random.Next () no es seguro para subprocesos y comenzará a devolver ceros cuando se rompa. He actualizado mi respuesta basada en esta información.
TODO el
1

Personalmente, soy un fanático de los métodos de extensión, por lo que usaría algo como esto (aunque en realidad no es una extensión, se ve similar):

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

}
Dan Champagne
fuente
1
A partir de C # 7.3, puede restringir su tipo genérico para que sea una enumeración: public static T Of<T>() where T : Enum docs.microsoft.com/en-us/visualstudio/releasenotes/…
nitzel
0

Adaptado como una extensión de clase aleatoria:

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

Ejemplo de uso:

var random = new Random();
var myEnumRandom = random.NextEnum<MyEnum>();
borja garcia
fuente
0

También puede emitir un valor aleatorio:

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

Pero deberías usar un mejor aleatorizador como el de esta biblioteca mía.

gsscoder
fuente