Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select a random element of an enum in D

Tags:

d

I have taken to selecting random values from enums like so:

import std.random : uniform;
import std.stdio : writefln;
import std.conv;

enum E {A, B, C}

int main(){
    auto select = cast(E)uniform(to!int(E.min), to!int(E.max));
    writefln("select %s", select);
    return 0;
}

This is surprisingly verbose, and prone to issues if any enum members take values outside the default (or larger than int).

Ideally I would take a range that represents the elements of the enum, and provide this to randomSample. However, this doesn't appear to be possible.

Is there a more idiomatic way to select a random value from an enum in D?

EDIT:

Using the answer provided by fwend, here is a template function that achieves what I want:

T RandomEnumElement(T)() if (is(T == enum)){
    auto members = [EnumMembers!T];
    return members[(uniform(0, members.length))];
}
like image 919
cmh Avatar asked Aug 27 '12 16:08

cmh


People also ask

How do you generate a random enum in Java?

This method use the java. util. Random to create a random value. This random value then will be used to pick a random value from the enum.

How do you use generic enums?

The enum is a default subclass of the generic Enum<T> class, where T represents generic enum type. This is the common base class of all Java language enumeration types. The transformation from enum to a class is done by the Java compiler during compilation.


1 Answers

import std.random : uniform;
import std.stdio : writefln;
import std.conv;
import std.traits;

enum E {A, B, C}

int main(){
    auto select = [EnumMembers!E][uniform(0, 3)];
    writefln("select %s", select);
    return 0;
}

Edit: if you need to use the enum values more than once, you can store them in a static immutable array first, otherwise the array will be built every time. That also allows you to get rid of the magic number 3.

(...)
int main(){
    static immutable Evalues = [EnumMembers!E];
    auto select1 = Evalues[uniform(0, Evalues.length)];
    writefln("select %s", select1);

    auto select2 = Evalues[uniform(0, Evalues.length)];
    writefln("select %s", select2);
    return 0;
}

Edit 2: As pointed out by Idan Arye, the template could be even terser:

T RandomEnumElement(T)() if (is(T == enum)){
    return [EnumMembers!T][(uniform(0, $))];
}

Edit 3: tgehr has suggested the following solution, which would build the lookup table once at compile time and avoid GC allocation altogether:

T RandomEnumElement(T)() if (is(T == enum)) {
    static immutable members = [EnumMembers!T];
    return members[uniform(0, $)];
}
like image 130
fwend Avatar answered Oct 26 '22 14:10

fwend