2017-03-15 4 views
4

Ich konvertiere ein Array in einen Datensatztyp. Etwas wie:F # Äquivalent von ++ Operator

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 

Dies funktioniert, aber hat den Nachteil, dass das Hinzufügen eines Wertes in die Mitte der Array-Ergebnisse in die manuelle Bearbeitung aller Index Referenzen danach wie folgt aus:

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 

Zusätzlich ist es einfach versehentlich die Indizes falsch erhalten.

Die Lösung kam ich mit ist:

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 } 

Dies funktioniert, aber ich mag nicht wirklich die ref Zelle für etwas, das nicht gleichzeitig ist. Gibt es einen besseren/saubereren Weg, dies zu erreichen?

Antwort

5

Sie könnten Mustervergleich verwenden.

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" 

Wenn das Hinzufügen eines weiteren Eintrag in dem Array Sie es, indem Sie das erste Match [|one; six; two; three; four; five|] einstellen würden.

Übrigens, für einen veränderbaren Index wie den, den Sie in Ihrem aktuellen Beispiel verwenden, können Sie ref vermeiden, indem Sie stattdessen das Schlüsselwort mutable verwenden, so;

let mutable index = -1 
let getIndex = 
    index <- index + 1 
    index 

Und wenn wir verstecken die wandelbar in der getIndex Funktion

let getIndex = 
    let mutable index = -1 
    fun() -> 
     index <- index + 1 
     index 
+0

Hmmm, ich bin verwirrt. Ich dachte, wenn man über ein veränderliches Objekt hinwegginge, musste es eine Referenzzelle sein. – mydogisbox

+2

Upside to tun es durch Mustererkennung - wenn Sie die Länge des Arrays ändern und das Muster nicht aktualisieren, erhalten Sie eine Compiler-Warnung, die Sie daran erinnert, es zu beheben. –

+4

@mydogisbox Ab F # 4.0 kannst du veränderbar anstelle von ref verwenden (der Compiler wird es für dich herausfinden, also wird es immer noch auf den Heap gesetzt - genauso wie wenn du ref im Code verwendest). Siehe https://blogs.msdn.microsoft.com/fsharpteam/2014/11/12/announcing-a-preview-of-f-4-0-and-the- visual-f-tools-in-vs-2015 /, Abschnitt namens Vereinfachte Verwendung von veränderbaren Werten – hlo

3

Sie könnten die Indizes lassen mit Pattern-Matching gehandhabt werden, und ein aktives Muster hinzufügen, wie folgt aus:

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" 
Verwandte Themen