Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a .NET construct like Java's enum.ordinal()?

Tags:

.net

enums

f#

If I have the following enum in F#:

type Note =
    | C = 0
    | D = 2
    | E = 4
    | F = 5
    | G = 7
    | A = 9
    | B = 11

But at some points, I need the ordinals of the items inside of it, such that Note.C = 1, Note.D = 2, etc. Obviously in other languages, foo.ordinal() would work, but in here is it necessary to use a function like such:

let getNoteOrdinal = function
    |Note.C -> 1
    |Note.D -> 2
    |Note.E -> 3
    |Note.F -> 4
    //etc

Is that function necessary or is there something better?

like image 223
LSM07 Avatar asked Feb 08 '19 14:02

LSM07


2 Answers

Enums in .NET are just a layer on top of an integral type, in this case your values are int.

Per the docs, you can do a simple conversion to get that value, for example:

let value = int Note.B

Where value in this case would be 11.

To find the ordinal, as you can make use of a built-in function that gives you an array of all the values in order and then find the index of the one you're after. For example:

let getNoteOrdinal (note: Note) =
    let values = Enum.GetValues(typeof<Note>)
    Array.IndexOf(values, note) + 1

let value = getNoteOrdinal Note.E

Where value in this case would be 3.

You can take this one step further as @ReedCopsey suggests and make a generic function that will give you the ordinal for any enum value:

let getEnumOrdinal (e: 'a when 'a : enum<'b> and 'a : equality) =    
    let values = Enum.GetValues(e.GetType())
    Array.IndexOf(values, e) + 1
like image 145
Charles Mager Avatar answered Sep 30 '22 04:09

Charles Mager


I suggest not using an enum at all in F# unless it is required for interoperation with another .NET language. You can use a discriminated union and store the note values in an array (this is a module level value that is evaluated once when the application starts). Then you can write functions that use the array.

type Note = C | D | E | F | G | A | B

let noteValues =
    [| C, 0
       D, 2
       E, 4
       F, 5
       G, 7
       A, 9
       B, 11 |]

let getNoteValue note =
    noteValues |> Array.find (fun (n, _) -> note = n) |> snd

let getNoteOrdinal note =
    noteValues |> Array.findIndex (fun (n, _) -> n = note) |> (+) 1

Example usage:

getNoteValue C // 0
getNoteValue D // 2

getNoteOrdinal C // 1
getNoteOrdinal D // 2
like image 45
TheQuickBrownFox Avatar answered Sep 30 '22 05:09

TheQuickBrownFox