I'm converting an array to a record type. Something like:
let value = [|"1";"2";"3";"Not a number";"5"|]
type ValueRecord = {
One: int32
Two: int32
Three: int32
Four: string
Five: int32 }
let convertArrayToRecord (x: string array) =
{ One = x.[0] |> Int.Parse
Two = x.[1] |> Int.Parse
Three = x.[2] |> Int.Parse
Four = x.[3]
Five = x.[4] |> Int.Parse }
let recordValue = convertArrayToRecord value
This works, but has the drawback that adding a value to the middle of the array results in manual editing of all index references thereafter like this:
let value = [|"1";"Not a number - 6";"2";"3";"Not a number";"5"|]
type ValueRecord = {
One: int32
Six: string
Two: int32
Three: int32
Four: string
Five: int32 }
let convertArrayToRecord (x: string array) =
{ One = x.[0] |> Int.Parse
Six = x.[1]
Two = x.[2] |> Int.Parse //<--updated index
Three = x.[3] |> Int.Parse //<--updated index
Four = x.[4] //<--updated index
Five = x.[5] |> Int.Parse } //<--updated index
let recordValue = convertArrayToRecord value
Additionally, its easy to accidentally get the indexes wrong.
The solution I came up with is:
let convertArrayToRecord (x: string array) =
let index = ref 0
let getIndex () =
let result = !index
index := result + 1
result
{ One = x.[getIndex ()] |> Int.Parse
Six = x.[getIndex ()]
Two = x.[getIndex ()] |> Int.Parse
Three = x.[getIndex ()] |> Int.Parse
Four = x.[getIndex ()]
Five = x.[getIndex ()] |> Int.Parse }
This works, but I really dislike the ref cell for something which isn't concurrent. Is there a better/cleaner way to accomplish this?
You could use pattern matching.
let convertArrayToRecord = function
| [|one; two; three; four; five|] ->
{
One = int one
Two = int two
Three = int three
Four = four
Five = int five
}
| _ ->
failwith "How do you want to deal with arrays of a different length"
When adding another entry to the array you'd adjust it by editing the first match to [|one; six; two; three; four; five|]
.
By the way, for a mutable index like the one you're using in your current example, you can avoid ref by using the mutable keyword instead, like so;
let mutable index = -1
let getIndex =
index <- index + 1
index
And if we hide the mutable inside the getIndex function
let getIndex =
let mutable index = -1
fun () ->
index <- index + 1
index
You could let the indexes be handled with pattern matching, and add an active pattern, like this:
let (|PInt32|_|) (s:string) =
let ok, i = Int32.TryParse(s)
if ok then Some(PInt32(s)) else None
let foo() =
match [|"1"; "2"; "Some str"|] with
| [|PInt32(x); PInt32(y); mystr|] ->
printfn "Yup"
| _ -> printfn "Nope"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With