在D中选择一个枚举的随机元素(Select a random element of an enum in D)

编程入门 行业动态 更新时间:2024-10-26 18:18:03
在D中选择一个枚举的随机元素(Select a random element of an enum 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; }

如果任何枚举成员的值超出了默认值(或大于int ),这是令人惊讶的详细,并且容易出现问题。

理想情况下,我将采用代表枚举元素的范围,并将其提供给randomSample 。 但是,这似乎不可能。

有没有更习惯的方式从D中的枚举中选择一个随机值?

编辑:

使用fwend提供的答案,下面是一个模板函数,它实现了我想要的功能:

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

I have taken to selecting random values from enums like so:

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

This is surprisingly verbose, and prone to issues if any enum members take values outside the default (or larger than int).

Ideally I would take a range that represents the elements of the enum, and provide this to randomSample. However, this doesn't appear to be possible.

Is there a more idiomatic way to select a random value from an enum in D?

EDIT:

Using the answer provided by fwend, here is a template function that achieves what I want:

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

最满意答案

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, $)]; } 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: if you need to use the enum values more than once, you can store them in a static immutable array first, otherwise the array will be built every time. That also allows you to get rid of the magic number 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: As pointed out by Idan Arye, the template could be even terser:

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

Edit 3: tgehr has suggested the following solution, which would build the lookup table once at compile time and avoid GC allocation altogether:

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

更多推荐

本文发布于:2023-07-22 02:14:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1216012.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:元素   Select   random   element   enum

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!