patternMinor
Hello Functional World: Counting occurrences of each letter
Viewed 0 times
countingeachoccurrencesletterworldfunctionalhello
Problem
Coming from a OO (C#) background, I am trying to learn some FP. To help me transition, I am trying to learn F#. I am taking baby steps.
I set myself a simple challenge to count the instances of each letter in a sentence, ordered alphabetically. ("Hello World" -> "[D, 1]; [E, 1]; [H, 1]; [L, 3]; [O, 2]; [R, 1]; [W, 1]; ").
My solution works but I can't help but thinking that I am not able to break out of an imperative style (my solution is based on Linq type thinking).
Does anyone know of a good source of challenges to help me get my teeth into learning this?
I set myself a simple challenge to count the instances of each letter in a sentence, ordered alphabetically. ("Hello World" -> "[D, 1]; [E, 1]; [H, 1]; [L, 3]; [O, 2]; [R, 1]; [W, 1]; ").
My solution works but I can't help but thinking that I am not able to break out of an imperative style (my solution is based on Linq type thinking).
open System
let getLetterCount xs =
xs |>
Seq.filter Char.IsLetter |>
Seq.map Char.ToUpper |>
Seq.groupBy id |>
Seq.sortBy fst |>
Seq.map (fun (k,v) -> (k, Seq.length v))
let tuplesToString = Seq.fold (fun a (k,v) -> a + sprintf "[%c, %i]; " k v) ""
printfn "%s" (tuplesToString (getLetterCount "Hello World"))Does anyone know of a good source of challenges to help me get my teeth into learning this?
Solution
As @Caridorc says, this is functional code, not imperative. It's basically pretty good.
It would be a good idea to include type annotations — for example,
I find the fold in
I'd rename both functions to have "counts" in their name. You can see the coherence in
It would be a good idea to include type annotations — for example,
(xs:string). If you wanted to (and I'm not saying it would be better to do so), you could drop xs as an explicit parameter and change the pipeline into a composition of functions. Also, you could sort before grouping for a slight simplification.I find the fold in
tuplesToString a bit hard to follow. In my opinion, using String.concat would be clearer, and it would also eliminate the extra space at the end of the line.I'd rename both functions to have "counts" in their name. You can see the coherence in
getLetterCounts |> countsToString.open System
let getLetterCounts:(string -> seq) =
Seq.filter Char.IsLetter >>
Seq.map Char.ToUpper >>
Seq.sort >>
Seq.groupBy id >>
Seq.map (fun (k, v) -> (k, Seq.length v))
let countsToString (counts:seq) =
[for k, v in counts -> sprintf "[%c, %i];" k v] |> String.concat " "
"Hello World" |> getLetterCounts |> countsToString |> printfn "%s"Code Snippets
open System
let getLetterCounts:(string -> seq<char * int>) =
Seq.filter Char.IsLetter >>
Seq.map Char.ToUpper >>
Seq.sort >>
Seq.groupBy id >>
Seq.map (fun (k, v) -> (k, Seq.length v))
let countsToString (counts:seq<char * int>) =
[for k, v in counts -> sprintf "[%c, %i];" k v] |> String.concat " "
"Hello World" |> getLetterCounts |> countsToString |> printfn "%s"Context
StackExchange Code Review Q#100366, answer score: 3
Revisions (0)
No revisions yet.