8

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

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

1 回答 1

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, $)];
}
于 2012-08-27T16:53:49.203 回答