Thread overview | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 13, 2014 std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
I'm confused about how to use random.uniform to select a member of an enum. Say I have an enum like enum Animals { cat = 0, dog = 1, chimpanzee = 2 } I want to select a random animal. So far I've been trying to do uniform(Animals), but every time I try to compile that, I get a "does not match any function template declaration" error. Am I misunderstanding how this function is meant to be used? |
February 13, 2014 Re: std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anton | On Thursday, 13 February 2014 at 02:02:38 UTC, Anton wrote: > I'm confused about how to use random.uniform to select a member of an enum. > > Say I have an enum like > > enum Animals > { > cat = 0, > dog = 1, > chimpanzee = 2 > } > > I want to select a random animal. So far I've been trying to do uniform(Animals), but every time I try to compile that, I get a "does not match any function template declaration" error. > > Am I misunderstanding how this function is meant to be used? The problem with using `uniform` for enums is that not all enums are sequential without holes, which would make the `uniform` implementation quite non-trivial if it were to try to handle enums generically. If you know your enum is sequential and doesn't have any holes, assume responsibility for that fact with a cast: --- enum Animals { cat = 0, dog = 1, chimpanzee = 2 } void main() { import std.random, std.stdio; foreach(immutable _; 0 .. 10) writeln(cast(Animals)uniform!"[]"(Animals.min, Animals.max)); } --- |
February 13, 2014 Re: std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anton | On Thursday, 13 February 2014 at 02:02:38 UTC, Anton wrote:
> Am I misunderstanding how this function is meant to be used?
Yeah, uniform takes two numerical arguments: a min and a max. It returns a value between the two, including the min, but not including the max. So
int a = uniform(0, 10); // returns 0,1,2,3,4,5,6,7,8, or 9.
You could do a random animal by doing `cast(Animals) uniform(0, 3);`, or getting fancier with reflection stuff... that'd take a few more lines, use __traits(getMember) and __traits(allMembers) to randomize rather than .min and .max because the latter wouldn't handle holes in the values.
|
February 13, 2014 Re: std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jakob Ovrum | On Thursday, 13 February 2014 at 02:14:02 UTC, Jakob Ovrum wrote:
> On Thursday, 13 February 2014 at 02:02:38 UTC, Anton wrote:
>> I'm confused about how to use random.uniform to select a member of an enum.
>>
>> Say I have an enum like
>>
>> enum Animals
>> {
>> cat = 0,
>> dog = 1,
>> chimpanzee = 2
>> }
>>
>> I want to select a random animal. So far I've been trying to do uniform(Animals), but every time I try to compile that, I get a "does not match any function template declaration" error.
>>
>> Am I misunderstanding how this function is meant to be used?
>
> The problem with using `uniform` for enums is that not all enums are sequential without holes, which would make the `uniform` implementation quite non-trivial if it were to try to handle enums generically.
>
> If you know your enum is sequential and doesn't have any holes, assume responsibility for that fact with a cast:
>
> ---
> enum Animals
> {
> cat = 0,
> dog = 1,
> chimpanzee = 2
> }
>
> void main()
> {
> import std.random, std.stdio;
>
> foreach(immutable _; 0 .. 10)
> writeln(cast(Animals)uniform!"[]"(Animals.min, Animals.max));
> }
> ---
Could you not simply select one at random by "name"? Even though
the values of the enum may not be sequential the keys are.
|
February 13, 2014 Re: std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frustrated | I guess I'm mostly confused because the description for one of the templates of std.random.uniform says "Returns a uniformly selected member of enum E. If no random number generator is passed, uses the default rndGen." So I was wondering why that functionality didn't seem to work as I thought it would. Otherwise, thanks for the workarounds. |
February 13, 2014 Re: std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anton | On Thursday, 13 February 2014 at 02:52:44 UTC, Anton wrote:
> I guess I'm mostly confused because the description for one of the templates of std.random.uniform says "Returns a uniformly selected member of enum E.
Oooh, I didn't know it had one of those, the documentation can be so hard to read sometimes.
Try this then:
auto randomAnimal = uniform!Animals();
The enum E there is a compile time argument, so you need the ! in there to pass them. (uniform(Animal) would be trying to send it as a run time argument which doesn't work for types)
|
February 13, 2014 Re: std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frustrated | On Thursday, 13 February 2014 at 02:30:47 UTC, Frustrated wrote: > Could you not simply select one at random by "name"? Even though > the values of the enum may not be sequential the keys are. Yeah, and there is apparently already an overload that does that. Regardless, I wrote a version that has an optimized path for sequential enums: https://gist.github.com/JakobOvrum/8968977 |
February 13, 2014 Re: std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jakob Ovrum | On Thursday, 13 February 2014 at 03:04:06 UTC, Jakob Ovrum wrote:
> On Thursday, 13 February 2014 at 02:30:47 UTC, Frustrated wrote:
>> Could you not simply select one at random by "name"? Even though
>> the values of the enum may not be sequential the keys are.
>
> Yeah, and there is apparently already an overload that does that.
>
> Regardless, I wrote a version that has an optimized path for sequential enums:
>
> https://gist.github.com/JakobOvrum/8968977
It's also worth noting that both the existing std.random.uniform and the one I posted would fail when the base type of the enum has mutable indirection.
|
February 13, 2014 Re: std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frustrated | On Thursday, 13 February 2014 at 02:30:47 UTC, Frustrated wrote:
> On Thursday, 13 February 2014 at 02:14:02 UTC, Jakob Ovrum wrote:
>> On Thursday, 13 February 2014 at 02:02:38 UTC, Anton wrote:
>>> I'm confused about how to use random.uniform to select a member of an enum.
>>>
>>> Say I have an enum like
>>>
>>> enum Animals
>>> {
>>> cat = 0,
>>> dog = 1,
>>> chimpanzee = 2
>>> }
>>>
>>> I want to select a random animal. So far I've been trying to do uniform(Animals), but every time I try to compile that, I get a "does not match any function template declaration" error.
>>>
>>> Am I misunderstanding how this function is meant to be used?
>>
>> The problem with using `uniform` for enums is that not all enums are sequential without holes, which would make the `uniform` implementation quite non-trivial if it were to try to handle enums generically.
>>
>> If you know your enum is sequential and doesn't have any holes, assume responsibility for that fact with a cast:
>>
>> ---
>> enum Animals
>> {
>> cat = 0,
>> dog = 1,
>> chimpanzee = 2
>> }
>>
>> void main()
>> {
>> import std.random, std.stdio;
>>
>> foreach(immutable _; 0 .. 10)
>> writeln(cast(Animals)uniform!"[]"(Animals.min, Animals.max));
>> }
>> ---
>
> Could you not simply select one at random by "name"? Even though
> the values of the enum may not be sequential the keys are.
import std.random, std.stdio, std.traits;
enum Animals
{
dog = "dog",
cat = "cat",
fox = "fox",
cow = "cow",
}
void main()
{
auto animals = [EnumMembers!Animals];
auto rnd = uniform!"[)"(0, animals.length);
writeln(animals[rnd]);
}
You have to wrap the EnumMembers template in an array, because tuples can only be sliced at compile-time, and uniform doesn't work at compile time.
|
February 13, 2014 Re: std.random.uniform for enums | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anton | On Thursday, 13 February 2014 at 02:52:44 UTC, Anton wrote:
> I guess I'm mostly confused because the description for one of the templates of std.random.uniform says "Returns a uniformly selected member of enum E. If no random number generator is passed, uses the default rndGen." So I was wondering why that functionality didn't seem to work as I thought it would.
>
> Otherwise, thanks for the workarounds.
Huh, disregard me. I didn't know there was a function for that.
|
Copyright © 1999-2021 by the D Language Foundation