How to count the occurrence of a specific character in a string

筅森魡賤 提交于 2019-12-23 17:37:35

问题


I'm not sure where to begin with the checking of a string for n occurrences of a specific char. I've laid out the basic outline of what I assume to be the framework for the function but the contents I'm not sure about?

let countCharFromNth (getStr : string)(chkdChar : char) = 
    if getStr.Length >=1 then 

    else printfn "Not enough arguments"

回答1:


Here is a tail recursive loop version.

let countCharFromNth (getStr : string)(chkdChar : char) = 
    let rec loop i count =
        if i < getStr.Length then 
            if getStr.[i] = chkdChar then loop (i+1) (count+1)
            else loop (i+1) count
        else count
    loop 0 0

It will get translated into an imperative loop by the compiler as all function calls are in the tail (last) position. While longer than the other versions, this is the most performant way of doing it as it does not create unnecessary intermediate collections.




回答2:


TL;DR

The 'most idiomatic' way is probably @Mark Seemanns:

let count x = Seq.filter ((=) x) >> Seq.length

The TooLong part

Note that this function is fully generic: x:'a -> (seq<'a> -> int) when 'a : equality, i.e. it counts occurrences of any x in a sequence of 'as, as long as 'a supports equality. Due to the right-hand side being a function, we also don't need to specify the string argument. This is called point-free style. The function is constructed by turning the = operator into a function by wrapping it in parentheses (think (=) = fun x y -> x = y), filtering the sequence with this predicate and calculating the resulting seqs length, i.e.

let count x xs =
    xs
    |> Seq.filter (fun x' -> x' = x)
    |> Seq.length

which is

let count x xs =
    Seq.length(Seq.filter (fun x' -> x' = x) xs)

Of course you can also leverage 'the C# way':

let count' x xs = System.Linq.Enumerable.Count(xs, fun x' -> x' = x)

Here you can't just turn the equality operator (=) into a predicate because the F# compiler needs to do some magic to turn the F# 'a -> bool into a Func<'a, bool>.

The usage is exactly the same:

count 'a' "abbbac"

or (more readable)

"abbbac" |> count 'a'
"abbac" |> count' 'b'

This (and better composability) is the reason functional programmers tend to reverse the order of arguments (count x xs vs. count xs x).

More exotic (and less performant) solutions:

let count'' (c : char) str =
    (System.Text.RegularExpressions.Regex.Matches(str, string c)).Count

let count''' (c : char) str =
    (String.length str) - (str.Replace(string c, "") |> String.length)



回答3:


Using fold is another option:

open System

let countCharFold targetChar = 
  Seq.fold (fun count ch -> if ch = targetChar then count + 1 else count) 0

[<EntryPoint>]
let main argv = 
  let text = "hello world"
  let ch = 'l'
  printfn "%d" (countCharFold ch text)

  Console.ReadLine() |> ignore
  0


来源:https://stackoverflow.com/questions/40022846/how-to-count-the-occurrence-of-a-specific-character-in-a-string

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!