2012-08-27 14 views
8

ho preso a selezionare valori casuali da enumerazioni modo:Selezionare un elemento casuale di un'enumerazione in 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; 
} 

Questo è sorprendentemente dettagliato, e soggetto a problemi se qualche membro enum assumono valori al di fuori del difetto (o superiore a int).

Idealmente vorrei prendere un intervallo che rappresenta gli elementi dell'enumerazione e fornire questo a randomSample. Tuttavia, questo non sembra essere possibile.

Esiste un modo più idiomatico per selezionare un valore casuale da un enum in D?

EDIT:

Utilizzando la risposta fornita da fwend, ecco un modello di funzione che consente di ottenere quello che voglio:

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

risposta

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

Edit: se avete bisogno di usare il enum valori più di una volta, è possibile memorizzarli prima in un array immutabile statico, altrimenti l'array verrà creato ogni volta. Ciò consente anche di liberarsi del numero magico 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: Come sottolineato da Idan Arye, il modello potrebbe essere ancora terser:

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

Modifica 3: tgehr ha suggerito la seguente soluzione, che avrebbe compilato la tabella di ricerca una volta al momento della compilazione ed evitato del tutto l'allocazione GC:

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

Attualmente la modifica non viene compilata, 'Evalue' ha bisogno di tipo 'E []'. – cmh

+0

@cmh Strano, compila bene con me. dmd 2.060 win7 – fwend

+0

Scusa funziona, ha bisogno dell'argomento quando si trova all'interno di una funzione template. – cmh

Problemi correlati