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は、コンパイル時にルックアップテーブルを1回作成し、GC割り当てを完全に回避する次のソリューションを提案しました。

T RandomEnumElement(T)() if (is(T == enum)) {
    static immutable members = [EnumMembers!T];
    return members[uniform(0, $)];
}
于 2012-08-27T16:53:49.203 に答える