216

Given an arbitrary enumeration in C#, how do I select a random value?

(I did not find this very basic question on SO. I'll post my answer in a minute as reference for anyone, but please feel free to post your own answer.)

mafu
  • 31,798
  • 42
  • 154
  • 247

11 Answers11

354
Array values = Enum.GetValues(typeof(Bar));
Random random = new Random();
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length));
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
81

Use Enum.GetValues to retrieve an array of all values. Then select a random array item.

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
mafu
  • 31,798
  • 42
  • 154
  • 247
  • 3
    `GetValues` now supports a type hint. `Enum.GetValues()`, even neater. – Yarek T Sep 20 '21 at 11:17
  • 1
    With `static T RandomEnumValue ()` **`where T : Enum`** you can limit the generic types to only `Enum`. Otherwise you could pass any type... ([More info](https://stackoverflow.com/questions/3786774/in-c-sharp-what-does-where-t-class-mean)) – Flimtix Mar 02 '22 at 09:29
8

Here's an alternative version as an Extension Method using 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());
        }
    }           
}

Two
One
Four
Four
Four
Three
Two
Four
One
Three

LW001
  • 2,452
  • 6
  • 27
  • 36
Aaron Hudon
  • 5,280
  • 4
  • 53
  • 60
  • 1
    You could also make it an extension: `public static T GetRandomEnumValue() where T : Enum => (T) Enum.GetValues(typeof(T)).OfType().OrderBy(_ => Guid.NewGuid()).FirstOrDefault();` That simplifies its usage to: `GetRandomEnumValue()` – Travis Dec 20 '20 at 23:42
  • 1
    I downvoted this question because it's not made clear why you would you generate N random GUIDs and then go through the trouble of sorting them, in light of a simple randomized index, which would've sufficed. – Zimano May 30 '21 at 14:01
  • 1
    @kerzek This is an extension and has a specified type! He limited it with `where T : Enum` to only enums. – Flimtix Mar 02 '22 at 09:47
6

Adapted as a Random class extension:

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

Example of usage:

var random = new Random();
var myEnumRandom = random.NextEnum<MyEnum>();
borja garcia
  • 141
  • 2
  • 3
5

You could just do this:

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

No need to store arrays

4

Call Enum.GetValues; this returns an array that represents all possible values for your enum. Pick a random item from this array. Cast that item back to the original enum type.

Tim Robinson
  • 53,480
  • 10
  • 121
  • 138
3

The modern answer combining this answer and its comment:

var randomMyEnum = GetRandom<MyEnum>();

the implementation:

public static class RandomExtensions
{
    private static Random Random = new Random();

    public static T GetRandom<T>() where T : struct, Enum
    {
        T[]? v = Enum.GetValues<T>();
        return (T)v.GetValue(Random.Next(v.Length));
    }
}
Nae
  • 14,209
  • 7
  • 52
  • 79
2

Here is a generic function for it. Keep the RNG creation outside the high frequency code.

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

Usage example:

System.Windows.Forms.Keys randomKey = RandomEnum<System.Windows.Forms.Keys>();
WHol
  • 2,206
  • 2
  • 13
  • 16
  • Having a static method which isn't threadsafe is pretty dangerous. – CodesInChaos Jul 30 '15 at 12:45
  • @CodesInChaos You're right. Random.Next() is not threadsafe and will start returning zeroes when it breaks. I've updated my answer based on this info. – WHol Aug 04 '15 at 15:23
1

A lot of these answers are pretty old and - correct me if I'm wrong - seem to work with some sketchy concepts like type erasure and dynamic type casting. However, as user Yarek T points out, there's no need for that with the generic overload of Enum.GetValues:

static Random random = new Random();

// Somewhat unintuitively, we need to constrain the type parameter to
// both struct *and* Enum - struct is required b/c the type can't be
// nullable, and Enum is required b/c GetValues expects an Enum type.
// You'd think that Enum itself would satisfy the non-nullable
// constraint, but alas, me compiler tells me otherwise - perhaps
// someone more knowledgeable can explain why this is in a comment?
static TEnum RandomEnumValue<TEnum>() where TEnum : struct, Enum
{
    TEnum[] vals = Enum.GetValues<TEnum>();
    return vals[random.Next(vals.Length)];
}

Or, like in borja garcia's answer, we can even write this as an extension of the random class

public static class RandomExtensions
{   
    public static TEnum NextEnumValue<TEnum>(this Random random)
        where TEnum : struct, Enum
    {
        TEnum[] vals = Enum.GetValues<TEnum>();
        return vals[random.Next(vals.Length)];
    }
}

And we can run the same test from mafu's answer:

Random random = new Random();
for (int i = 0; i < 10; i++) {
    var day = random.NextEnumValue<System.DayOfWeek>();
    Console.WriteLine(day.ToString());
}

Potential output:

Thursday
Saturday
Sunday
Sunday
Sunday
Saturday
Wednesday
Monday
Wednesday
Thursday
Josie Thompson
  • 5,608
  • 1
  • 13
  • 24
0

Personally, I'm a fan of extension methods, so I would use something like this (while not really an extension, it looks 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
  • 890
  • 2
  • 17
  • 37
  • 2
    As of C#7.3 you can constraint your generic type to be an enum: `public static T Of() where T : Enum` https://learn.microsoft.com/en-us/visualstudio/releasenotes/vs2017-preview-relnotes#csharp – nitzel Aug 02 '18 at 09:38
-1

You can also cast a random value:

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

But you should use a better randomizer like the one in this library of mine.

gsscoder
  • 3,088
  • 4
  • 33
  • 49
  • Gah, almost. This fails for non-auto numbered enums. GetValues return you a list, Its safe to select a random element from that. – Yarek T Sep 20 '21 at 11:19