Select a random listing item in D

I selected random values ​​from the enumerations as follows:

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 error prone if any members of the enumeration take values ​​outside the default value (or greater than int ).

Ideally, I would take a range that represents enumeration elements, and provide this with a randomSample . However, this is not possible.

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

EDIT:

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

 T RandomEnumElement(T)() if (is(T == enum)){ auto members = [EnumMembers!T]; return members[(uniform(0, members.length))]; } 
+8
d
source share
1 answer
 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 enumeration values ​​more than once, you can first save them in a static immutable array, otherwise the array will be built every time. It 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 Idan Ari noted, the pattern can be even:

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

Edit 3 : tgehr proposed the following solution, which would collect the lookup table once at compile time and not allocate GC at all:

 T RandomEnumElement(T)() if (is(T == enum)) { static immutable members = [EnumMembers!T]; return members[uniform(0, $)]; } 
+9
source share

All Articles