1

F#を勉強しようとしています。そして、簡単なsoundex式の助けが必要です。Simplified (American とも呼ばれる) soundex には、次のルールセットを使用しています。

1.) Assign characters to classes
2.) Remove duplicate values here, e.g. 222 becomes 2  
3.) Replace first encoded char with first char  
4.) Remove nulls
5.) Truncate ot pad to totally 4 characters

現在、私はルール番号にこだわっています。2. 再帰式を使おうと思っていました。私は現在 F# の初心者なので、私の問題に対する洗練された解決策をあなたに尋ねようと思います。テキストを soundex に変換する私のアプローチ全体が目標から外れているのではないでしょうか?

どんな提案でも大歓迎です:)

これが私のコードです:

let Simplified (name:string) =
let ca = name.ToLower().ToCharArray()
new string(
    Array.map(
        fun e ->
        match e with                                                          
            | 'a' | 'e' | 'i' | 'o' | 'u' | 'y' | 'w' | 'h' -> '0'
            | 'b' | 'f' | 'p' | 'v'                         -> '1'
            | 'c' | 's' | 'k' | 'g' | 'j' | 'q' | 'x' | 'z' -> '2'
            | 'd' | 't'                                     -> '3'
            | 'l'                                           -> '4'
            | 'm' | 'n'                                     -> '5'
            | 'r'                                           -> '6'
            |  _                                            -> ' '
        )  ca
  //|> fun s -> TODO: Remove duplicates here
    |> fun s -> Array.set s 0 (ca.[0]) 
                Array.choose(fun e -> if e <> '0' then Some(e) else None) s   
)  
|> fun s -> (
            match s.Length with                                               
                | x when x < 3 -> s.PadRight(4, '0')
                | _ -> s.Substring(0, 4)
            ).ToUpper()
4

4 に答える 4

4

結果として生じる重複を削除したい場合 ( zeuxcgのソリューションの 2 番目のオプション)、これを再帰関数として直接実装することもできます (アキュムレータ パラメータを使用)。これはパターン マッチングをうまく示しているので、F# を学習しながら試してみることをお勧めします。

let removeConsequentDuplicates list = 
  let rec loop acc list =
    match list with 
    | x1::x2::xs when x1 = x2 -> loop acc (x2::xs)
    | x::xs -> loop (x::acc) xs
    | _ -> acc |> List.rev
  loop [] list

このバージョンはリストで動作しますが、配列で作業しているため、おそらく命令型バージョンが必要になるでしょう。次のようなシーケンス式を使用できます。

let removeConsequentDuplicates (arr:_[]) = 
  let rec loop last i = seq {
    if i < arr.Length - 1 && last = arr.[i] then 
      yield! loop last (i+1)
    elif i < arr.Length - 1 then
      yield arr.[i]
      yield! loop (arr.[i]) (i + 1) }
  [| if arr.Length > 0 then
       yield arr.[0]
       yield! loop arr.[0] 0 |]

補足として、あなたの構文は少し読みにくいと思います。... |> fun s -> ...を書くのは良い考えではないと思いますlet s = ... in ...。次のようなものを書くことをお勧めします (あなたのコードを完全に理解しているかどうかはわかりませんが、アイデアはわかります...):

let Simplified (name:string) =
  let ca = name.ToLower().ToCharArray()
  let s = 
    ca |> Array.map (function
            | '0' ... )
       |> removeConsequentDuplicates
  Array.set s 0 (ca.[0])
  let s = s |> Array.choose(fun e -> if e <> '0' then Some(e) else None)
  let s = (new String(s)).ToUpper()
  match s.Length with                                               
  | x when x < 3 -> s.PadRight(4, '0')
  | _ -> s.Substring(0, 4)
于 2011-01-28T16:40:32.893 に答える
2

再帰ではなくループを使用して配列を使用して、連続する重複を削除します。最も単純には、次のようなシーケンス式で行います。

let removeDuplicates (xs: _ []) =
  [|if xs.Length > 0 then yield xs.[0]
    for i=1 to xs.Length-1 do
      if xs.[i] <> xs.[i-1] then
        yield xs.[i]|]
于 2011-01-30T22:08:21.007 に答える
1

配列からすべての重複を削除する (一意の要素を残す) 場合は、次のようにします。

arr |> Seq.distinct |> Seq.toArray

連続する重複を削除したい場合、解決策はより困難です。これは私が思いつくことができる最も簡単なものです:

let unique list =
    list
    |> List.fold (fun acc e ->
        match acc with
        | x::xs when x = e -> acc
        | _ -> e::acc) []
    |> List.rev

配列を使用してArray.toList、およびArray.ofListまたは使用してArray.fold、一致式とリストの構築を変更できます。コードが読みにくいので、リスト バージョンを投稿します。

代替ソリューションにはSeq.pairwise、次のものが含まれます。

let unique arr =
    if Array.isEmpty arr then
        arr
    else
        Array.append [|arr.[0]|] (
            arr
            |> Seq.pairwise
            |> Seq.toArray
            |> Array.choose (fun (p, n) -> if p = n then None else Some n))
于 2011-01-28T13:26:21.740 に答える
1

Seq.fold はあなたの友達です。

let soundex (text : string) = 
    let choose = 
        function 
        | 'b' | 'f' | 'p' | 'v' -> Some "1" 
        | 'c' | 'g' | 'j' | 'k' | 'q' | 's' | 'x' | 'z' -> Some "2" 
        | 'd' | 't' -> Some "3" 
        | 'l' -> Some"4" 
        | 'm' | 'n'  -> Some "5"
        | 'r' -> Some "6"
        | _ -> None 

    let fold state value = 
        match state with
        | i :: _ when i = value -> state
        | _ -> value :: state

    let t = text.Substring(1).ToLower() |> Seq.choose choose |> Seq.fold fold [] |> Seq.toList |> List.rev |> String.concat ""

    text.Substring(0,1) + t.PadRight(3, '0').Substring(0, 3)

これは、soundex のウィキペディアの記事に基づいています。

于 2011-01-31T09:59:21.093 に答える