2012-08-27 30 views
8

he llevado a la selección de valores aleatorios a partir de las enumeraciones de este modo:Seleccionar un elemento aleatorio de una enumeración en 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; 
} 

Esto es sorprendentemente detallado y propensos a problemas si algún miembro de enumeración toman valores fuera del defecto (o mayor que int).

Lo ideal sería tomar un rango que representa los elementos de la enumeración, y proporcionar esto a randomSample. Sin embargo, esto no parece ser posible.

¿Hay alguna forma más idiomática de seleccionar un valor aleatorio de una enumeración en D?

EDIT:

Usando la respuesta proporcionada por fwend, aquí es una función de plantilla que logra lo que quiero:

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

Respuesta

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

Editar: si necesita utilizar el enum valores más de una vez, puede almacenarlos en una matriz inmutable estática primero, de lo contrario, la matriz se construirá todo el tiempo. Esto también permite a deshacerse del número mágico 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; 
} 

Editar 2: Como ha señalado Idan Arye, la plantilla podría ser aún más concisa:

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

Editar 3: tgehr ha sugerido la siguiente solución, que crearía la tabla de búsqueda una vez en tiempo de compilación y evitaría la asignación de GC por completo:

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

Actualmente la edición no compila, las necesidades de 'Evalues ​​'teclean' E [] '. – cmh

+0

@cmh Extraño, compila muy bien conmigo. dmd 2.060 win7 – fwend

+0

Disculpa, funciona, necesita el argumento cuando está dentro de una función de plantilla. – cmh

Cuestiones relacionadas