3

区切られたデータの文字列があります。

a~b~c~d~e~f~g~h~i~j~k~l~... 
dog~cat~fish~parrot~mother~father~child~grandparent~...
hello~hi~greetings~yo

タイプのレコードの配列/シーケンスにデータをロードしたい

type myType {
    first: string;
    second: string;
    third: string;
    fourth:string;
}

そのため、配列/シーケンスに 3 つのオブジェクトができてしまいます。これを行うためにforループをいじっていますが、それはかなり不可欠だと感じています。機能的なイディオムを使用してこれを達成するにはどうすればよいですか?

編集:区切られた項目の数は常に 4 の倍数である必要がありますが、区切られたデータは可変長である可能性があることを明確にする必要がありました。 type を取得し、すべてのデータが消費されると、Array/seq を返します。

編集2:だから私はこのようなものになってしまった

let createValues(data: string) =               
    let splitValues(valueString) = 
        let rec splitData acc = function
            | a :: b :: c :: d :: xs -> splitData ({ first=a; second=b; third=c; fourth=d } :: acc) xs
            | [] -> acc
            | _ -> failwith "uneven data"
        splitData [] valueString
    splitValues (data.Split [|'~'|] |> Array.toList)

どうも

4

3 に答える 3

5

タイプには単一の文字しか含まれていません-データが常に単一の文字で構成されていると仮定すると、区切り記号は不要です。データをタイプのリストにマップする 1 つの方法を次に示します。これは、データ内の文字数が 4 で割り切れる場合にのみ機能しますが、可変サイズの入力で機能します。

let data = "a~b~c~d~e~f~g~h~i~j~k~l~m~n~o~p"

let splitData data =
    let rec aux acc = function
        | a::b::c::d::xs -> aux ({ first=a; second=b; third=c; fourth=d } :: acc) xs
        | [] -> acc
        | _ -> failwith "uneven data"
    aux [] data

let output = splitData (data.Replace("~","").ToCharArray() |> Array.toList)
于 2013-03-29T18:56:03.403 に答える
3

優れた回答がすでに与えられていますが、入力データ形式が仕様に正確であることを確認する必要がある場合は、次のように解析できます。

let readObjects inputString =
    let rec readObjectsAux input =
        seq {
            match input with
            | a :: '~' :: b :: '~' :: c :: '~' :: d :: rest ->
                yield { first = a; second = b; third = c; fourth = d }
                match rest with
                | '~' :: rest -> yield! (readObjectsAux rest)
                | [] -> ()
                | _ -> failwith "bad input"
            | [] -> ()
            | _ -> failwith "bad input"
        }
    readObjectsAux <| (List.ofSeq inputString)

このようにして、キャラクターが常に 4 人組になり、常に正確に 1 つの'~'.

于 2013-03-30T02:21:42.380 に答える
2

各フィールドが正確に 1 つcharである場合 (この場合、区切り文字にポイントが表示されないため、省略しました)、次のようにすることができます。

File.ReadAllLines(@"C:\data.txt")
  |> Array.mapi (fun n line ->
    match line.ToCharArray() with
    | [|a;b;c;d;e;f;g;h;i;j;k;l|] ->
      let t1 = {first=a; second=b; third=c; fourth=d}
      let t2 = {fifth=e; sixth=f; seventh=g; eighth=h}
      let t3 = {ninth=i; tenth=j; eleventh=k; twelfth=l}
      (t1, t2, t3)
    | _ -> failwithf "Can't parse line %d" (n+1))

区切り文字が必要な場合は、次のように変更できます。

    match line.Split('~') with
    | [|a;b;c;d;e;f;g;h;i;j;k;l|] ->
      let t1 = {first=a.[0]; second=b.[0]; third=c.[0]; fourth=d.[0]}
      ...
于 2013-03-29T18:44:33.027 に答える