Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a simple and safe way to choose a random enum value?

I needed to choose a random value from an enum. In some article about Nim I found this solution:

import random

type Animal = enum
  Cat
  Dog
  Cow

echo rand(0..2).Animal

But this doesn't scale well: If some values are added to or removed from the enum, we have to adjust the upper number.

We can even get a runtime error:

import random

type Animal = enum
  Cat
  Dog

randomize(123)

while true:
  echo rand(0..2).Animal
Cat
Cat
Dog
…/example.nim(10) example
…/.choosenim/toolchains/nim-1.4.4/lib/system/fatal.nim(49) sysFatal
Error: unhandled exception: value out of range: 2 notin 0 .. 1 [RangeDefect]

I am looking for a simple way to choose a random value from an enum1 that is safe, meaning that if it compiles, it is guaranteed that there will be no RangeDefect or similar runtime error.

I would also be interested to know if there is a compiler setting that generates at least a warning in the above example.

The compiler seems to be capable of this in principle:

Animal(5)

→ Error: 5 can't be converted to Animal

After reading in https://nim-lang.org/docs/random.html about

  • rand,Rand,range[]
  • rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]
  • rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]
  • rand,typedesc[T]

I thought that one of the following could work, but they don't compile:

rand(Animal)

→ Error: type mismatch: got <type Animal>
rand(range(Animal))

→ Error: type mismatch: got <type Animal> but expected 'range = range (None)'
rand(range[Animal])

→ Error: expected range
rand(Slice[Animal])

→ Error: type mismatch: got <type Slice[example.Animal]>
rand(Slice(Animal))

→ Error: type mismatch: got <type Animal> but expected 'Slice = CompositeTypeClass'

This does work, but I guess it is unnecessarily inefficient, because it needs to allocate and fill a sequence:

import sequtils

echo sample(Animal.toSeq)

1I'm assuming no enums with holes, which I'm aware are another issue.

like image 718
mkrieger1 Avatar asked Mar 28 '21 13:03

mkrieger1


People also ask

How do you use random enums?

To use the random.Pass the enum to the list() class to convert it to a list. Pass the list to the random. choice() method to get a random enum member.

How do you randomize enums in Systemverilog?

Show activity on this post. typedef enum int { IPV4_VERSION = 0, IPV4_IHL = 1, IPV4_TOTAL_LENGTH = 2,IPV4_CHECKSUM = 3 } ipv4_corrupton; ipv4_corrupton ipv4_corrupt; std::randomize(ipv4_corrupt) with {ipv4_corrupt dist { IPV4_VERSION :=2,IPV4_IHL := 4,IPV4_TOTAL_LENGTH := 4,IPV4_CHECKSUM := 2}; };

How do you get the random value of an enum?

Random Enum Value with static Method First, we'll create a static function that returns a random-generated value from a specific enum set. Enum values represent a set of constants; yet, we can still declare static methods within the enum class body. We'll utilize a static method as a helper to generate a random enum value.

What is the use of enum valueOf () method?

valueOf () method returns the enum constant of the specified string value, if exists. enum can contain a constructor and it is executed separately for each enum constant at the time of enum class loading. We can’t create enum objects explicitly and hence we can’t invoke enum constructor directly.

What is the difference between ENUM and randomenumgenerator in Java?

The difference is that the RandomEnumGenerator class has a constructor that expects an enum type from which to get the constant values. We could generate a random direction using the RandomEnumGenerator class as follows:

How to get all values present in enum in Java?

values () method can be used to return all values present inside enum. Order is important in enums.By using ordinal () method, each enum constant index can be found, just like array index. valueOf () method returns the enum constant of the specified string value, if exists.


Video Answer


1 Answers

A straightforward solution is to use low and high:

rand(Animal.low..Animal.high)

Using a generic proc allows to write rand(Animal):

import random

type Animal = enum
  Cat
  Dog
  Cow

proc rand(T: typedesc): T =
  rand(T.low..T.high)

randomize(123)

for _ in 1..6:
  echo rand(Animal)

Output:

Cat
Cat
Dog
Cow
Cow
Dog
like image 151
mkrieger1 Avatar answered Sep 28 '22 16:09

mkrieger1