收藏品丰富

时间:2018-11-19 19:12:47

标签: f#

原始问题

我想使用F#在一组单词中找到辅音与元音的接近程度。例如,在单词“ top”中,T是元音的(-1:1),P是元音的(1:1)。

相对于最近的元音,对中的第一个数字是位置,第二个数字是其在该位置的次数。

在“辅音”中,C为(-1:1),N为(1:3),(-2:1),(-1、1),S为(2:1),(-1 :1),(3:1),T为(2:1)。

我怀疑我必须结合使用groupBy,findIndex和countBy。

type ConsonantPos = { Name: string
                      BeforeVowel: int
                      AfterVowel: int }

let isVowel (x:string) =
    List.contains x ["a";"e"; "i"; "o"; "u"]

let consonantPosVsVowel x lst = 
      let rec getConsonanatPos x beforeVowel afterVowel currentPos lst = 
          match lst with
            | [] -> {Name = x; BeforeVowel = beforeVowel; AfterVowel = afterVowel}
            | h::t -> 
              if isVowel h then
                {Name = x; BeforeVowel = beforeVowel; AfterVowel = afterVowel}
              else 
                getConsonanatPos  x (beforeVowel - 1) (afterVowel + 1) (currentPos + 1) t

      getConsonanatPos x 0 0 0 lst


["b"; "a"; "c"] |> consonantPosVsVowel "b"
// val it : ConsonantPos = {Name = "b"; BeforeVowel = -1; AfterVowel = 1;}
["b"; "c"; "d"; "e"; "f"; "g"] |> consonantPosVsVowel "b"
// val it : ConsonantPos = {Name = "b"; BeforeVowel = -3; AfterVowel = 3;}

修订版解决方案

截至2018年11月21日,这两个建议对于我最初指定的问题均行之有效。

当然,这个问题只是我正在编写的程序的一部分。当我扩展程序并浏览数据BEEP时,一种响应被证明更易于重用:这就是我标记为答案的响应。

事实证明,我的问题是我缺乏理解并且无法使用收藏集。

2 个答案:

答案 0 :(得分:2)

尝试一下:

let isVowel (x:char) =
    List.contains x ['a';'e'; 'i'; 'o'; 'u']

let countConsonants (word:string) =
    let vowelsp, consonants =
        word
        |> Seq.mapi(fun i c-> c,i )
        |> Seq.toArray
        |> Array.partition (fst >> isVowel)
    let vowels = vowelsp |> Array.map snd
    consonants
    |> Seq.collect (fun (c,i) -> 
        match vowels |> Array.tryFindIndex ((<) i) with
        | None   -> [ vowels.Length - 1 ]
        | Some j -> [ j - 1     ; j     ]
        |> Seq.choose (fun j -> 
            if j < 0 then None else
            Some(c, i - vowels.[j])
        )
    )
    |> Seq.countBy id
    |> Seq.map (fun ((l,p), c) -> (l,(p, c)) )
    |> Seq.groupBy fst
    |> Seq.map (fun (l, s) -> l, s |> Seq.map snd |> Seq.toArray)
    |> Seq.toArray

"consonants"
|> countConsonants
|> Seq.iter (printfn "%A")

答案 1 :(得分:1)

这是一种略有不同的方法,它以不同的方式分解任务。

  • 使用尾部(负距离,正向)和头部将元素映射到自身 (正向,反向)。这是通过递归函数和两个 蓄电池
  • 过滤结果列表以查找不是元音的元素
  • 将其映射到代表负距离和正距离的选项对,其中 另一个递归函数,并将这些对收集到一个平面列表中 再次转移他们的价值观时
  • 将此列表按元素分组,然后将结果映射到距离和出现次数的元组

let genTail2 xss =
    let rec aux accl accr = function
    | [] -> List.rev accr
    | x::xs -> aux (x::accl) ((x, (xs, accl))::accr) xs
    aux [] [] xss
// val genTail2 : xss:'a list -> ('a * ('a list * 'a list)) list

let dist2 pred (x, (ls, rs)) =
    let rec aux n i = function
    | [] -> None
    | y::ys -> if pred y then Some(x, n) else aux (n + i) i ys
    aux -1 -1 ls, aux 1 1 rs
// val dist2 :
//   pred:('a -> bool) ->
//     x:'b * ('a list * 'a list) -> ('b * int) option * ('b * int) option

let tuple2List = function
| None, None -> []
| Some x, None | None, Some x -> [x]
| Some x, Some y -> [y; x]
// val tuple2List : 'a option * 'a option -> 'a list

let isVowel = ResizeArray['a';'e';'i';'o';'u'].Contains
// val isVowel : (char -> bool)    

"consonants"
|> fun s -> s.ToLower()
|> Seq.toList
|> genTail2
|> List.filter (fst >> isVowel >> not)
|> List.collect (dist2 isVowel >> tuple2List)
|> Seq.groupBy fst
|> Seq.map (fun (x, xs) -> x, Seq.countBy snd xs)
|> Seq.iter (printfn "%A")