【问题标题】:Select a random element of an enum in D选择 D 中枚举的随机元素
【发布时间】:2012-08-27 16:29:40
【问题描述】:

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

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

【问题讨论】:

    标签: d


    【解决方案1】:
    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, $))];
    }
    

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

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

    【讨论】:

    • 当前编辑无法编译,Evalues 需要输入E[]
    • @cmh 奇怪,它编译得很好。 dmd 2.060 win7
    • 道歉它确实有效,它在模板函数中需要参数。
    • 代替Evalues.length(或3,这更糟),您还可以使用美元($)符号 - represents the array's length
    猜你喜欢
    • 2014-08-06
    • 1970-01-01
    • 1970-01-01
    • 2018-07-07
    • 2019-03-20
    • 2020-09-10
    • 2013-10-20
    相关资源
    最近更新 更多