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))];
}
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.
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.
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, $)];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With