在D中选择枚举的随机元素

时间:2012-08-27 16:29:41

标签: d

我已经从枚举中选择了随机值,如下所示:

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

这是令人惊讶的冗长,如果任何枚举成员获取超出默认值(或大于int)的值,则容易出现问题。

理想情况下,我会使用一个代表枚举元素的范围,并将其提供给randomSample。但是,这似乎不可能。

是否有更惯用的方式从D中的枚举中选择随机值?

修改

使用fwend提供的答案,这是一个实现我想要的模板功能:

T RandomEnumElement(T)() if (is(T == enum)){
    auto members = [EnumMembers!T];
    return members[(uniform(0, members.length))];
}

1 个答案:

答案 0 :(得分:9)

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

编辑:如果需要多次使用枚举值,可以先将它们存储在静态不可变数组中,否则每次都会构建数组。这也可以让你摆脱神奇的数字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;
}

编辑2 :正如Idan Arye所指出的,模板可能更为简洁:

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

编辑3 tgehr 提出了以下解决方案,它将在编译时构建一次查找表并完全避免GC分配:

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