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 的倍数。因此,每次迭代时,我希望剥离 4 条输入数据,将它们加载到输入所有数据后,返回一个数组/序列。

编辑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

您的类型仅包含单个字符 - 假设数据始终由单个字符组成,则不需要分隔符。这是将数据映射到类型列表的一种方法,这仅适用于数据中的字符数量可被 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)

通过这种方式,您可以确保您的角色始终以四重奏形式出现,并且它们始终被精确地隔开'~'

于 2013-03-30T02:21:42.380 回答
2

如果每个字段都是一个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 回答