count the number of vowels in a given string F# - string

I need a method using List.fold that will count the number of vowels in a given string.
So far I have this method.
let vowels = ['a';'e';'i';'o';'u']
let isVowel =
fun c -> vowels |> List.contains c
let count =
String.filter isVowel
>> String.length
printfn "%A" (count "aaaa")
It works fine, but I cannot figure out how to make a List.fold one using the same isVowel method. Here is my try.
The code below does not work, its purpose is to reflect my idea. Since the fold method applies the isVowel() which returns a true/false on each char in the string, if the condition is true it will add 1 to the accumulator which is the 0 parameter. When I try to use if else insinde the anon function I get an error.
let isVowel x =
match x with
| 'a' -> true
| 'e' -> true
| 'i' -> true
| 'o' -> true
| 'u' -> true
| _ -> false
let countNumOfVowels =
List.fold (fun (isVowel) (x) -> x + 1) 0 ["aaaa"]

You are trying to fold a list but your source is actually a string.
A string can be interpreted as a sequence of chars if you use Seq.fold:
"abracadabra" |> Seq.fold (fun i c -> if isVowel c then i + 1 else i) 0
// val it : int = 5

This is what I was looking for. Thanks Gus!
let countNumOfVowels str =
List.fold (fun (x: int) (c: char) -> if (isVowel c) then x + 1 else x) 0 (Seq.toList str)
countNumOfVowels "Hello"
> countNumOfVowels "Hello";;
val it : int = 2

Related

How to delete all char of a string in OCaml

Is there an easy way to delete all occurrences of a char in an OCaml string ?
I thought I could use this clean function :
let clean =
function
| ' ' | '[' | ']' | '\n' | '>' -> ''
| x -> x
in
But you can't use '' in OCaml.
So I came with this solution :
let delete =
function
| ' ' | '[' | ']' | '\n' | '>' -> true
| _ -> false
in
let char_list, size =
String.fold_left
(fun (acc, count) c ->
if delete c then acc, count
else c::acc, count+1) ([],0) path_string
in
let char_list = ref ## List.rev char_list in
let aux() =
match !char_list with
| [] -> failwith "unexpected"
| x :: xs -> char_list := xs; x
in
let cleaned_string = String.init size (fun _ -> aux()) in
cleaned_string
But it's big - with python it's just s.replace('>','') to suppress one - and only work with OCaml 4.13 which is not supported for my installation.
If you want to build a string dynamically, you should use a buffer
let remove_chars erase s =
let b = Buffer.create 10 in
String.iter (fun c -> if not (erase c) then Buffer.add_char b c);
Buffer.contents b
(Building a list of characters is extremely inefficient.)
The closest equivalent to python might be Str.global_replace:
Str.(global_replace (regexp ">") "" s)
or to do multiple characters at once you could do something like:
Str.(global_replace (regexp "[youChar1yourChar2yourChar3]") "" s)
So in your case :
Str.(global_replace (regexp "[][> \n]") "" s)

convert string of digits to int in Haskell

I am trying to write this function in Haskell called scanString, which takes a string and convert it into int if it's composed of only digits and should return 0 otherwise.
For example, scanString "123" = 123 but scanString "12a" = 0.
Here's my implementation so far:
scanChar :: Char -> Int
scanChar c
| 48 <= fromEnum c && fromEnum c <= 57 = (fromEnum c) - fromEnum '0'
| otherwise = 0
scanString :: String -> Int
scanString str = case str of
[] -> 0
x:xs
| 48 <= fromEnum x && fromEnum x <= 57 ->
((scanChar x) * (10 ^ ((length str) -1 ))) + scanString xs
| otherwise -> 0
This code does not do the right thing as scanString "3a" would give 30.
Is there a way (like in Java or Python) where one can simply terminate a function and return a value? Of course, advice on the implementation on this function would be awesome!
Thanks in advance!
The main problem here I think is that you let scanChar :: Char -> Int return both a zero for the zero character ('0') as well as for other characters. As a result the scanString has to include extra logic and this makes it only more complex.
So we can clean the scanChar by for instance returning a -1 (or we could let it return a Maybe Int and let it return Nothing, regardless how you exactly specify it, the key is to try to encapsulate the checking logic in one function, such that we no longer have to care about it). So for example:
scanChar :: Char -> Int
scanChar c | '0' <= c && c <= '9' = fromEnum c - fromEnum '0'
| otherwise = -1
So now we can encapsulate all the digit parsing logic in scanChar. Now we still need to implement scanString :: String -> Int. This can be done by writing an extra function that works with an accumulator. For example:
scanString :: String -> Int
scanString = go 0
where go a s = ...
So here go acts as a function to emulate some sort of while loop. The a parameter is the accumulator, a parameter we pass through recursive calls and each time we can update it with more data. Initially we set it to zero.
The go function has basically three cases:
the end of the string is reached, we can return the accumulator;
the first character of the string is not a digit, we return 0; and
the first character of the string is a digit, we multiply the accumulator with 10, add the parsed value, and perform recursion on the tail of the string.
We can thus implement those three cases like:
scanString :: String -> Int
scanString = go 0
where go a [] = a
go a (x:xs) | 0 <= sc && sc <= 9 = go (10*a+sc) xs
| otherwise = 0
where sc = scanChar x
So you're limited by the specification of the problem that the outermost question be of type String -> Int, but that doesn't mean that your helper function scanChar can't return Maybe Int.
So let's look at doing that:
scanChar :: Char -> Maybe Int
scanChar c
| 48 <= fromEnum c && fromEnum c <= 57 = Just $ (fromEnum c) - fromEnum '0'
| otherwise = Nothing
Now, using the approach in the other answer:
scanString :: String -> Int
scanString = go 0
where go a [] = a
go a (x:xs) = case (scanChar x) of
Nothing -> 0
Just d -> go (10*a + d) xs
where sc = scanChar x
Why not
scanString :: String -> Int
scanString x = if all (`elem` "0123456789") x
then read x :: Int
else 0
Note: it will not read negative integers.
Or:
import Data.Char (isDigit)
scanString' :: String -> Int
scanString' x = if all isDigit x
then read x :: Int
else 0
Also a simple solution here using readMaybe.
You can make the following into a function with one parameter that is a string. This function will take only digits out of the string and pack them into another string which is then then converted.
[read [d | d <- "12a", elem d "1234567890"] :: Int] !! 0
Yields 12

F# - Remove duplicate characters after first in string

What I am trying to do is to remove duplicates of a specific given char in a string but letting the first char to remain. I.e:
let myStr = "hi. my .name."
//a function that gets a string and the element to be removed in the string
someFunc myStr "."
where someFunc returns the string showen as below:
"hi. my name"
It is easy to remove duplicates from a string, but is there a way to remove the duplicates but letting the first duplicated element remain in the string?
Here's one approach:
let keepFirst c s =
Seq.mapFold (fun k c' -> (c', k||c<>c'), k&&c<>c') true s
|> fst
|> Seq.filter snd
|> Seq.map fst
|> Array.ofSeq
|> System.String
let example = keepFirst '.' "hi. my .name."
let someFunc (str : string) c =
let parts = str.Split([| c |])
if Array.length parts > 1 then
seq {
yield Array.head parts
yield string c
yield! Array.tail parts
}
|> String.concat ""
else
str
Note that the character is given as char instead of a string.
let someFunc chr (str:string) =
let rec loop (a: char list) b = function
| [] -> a |> List.rev |> System.String.Concat
| h::t when h = chr -> if b then loop a b t
else loop (h::a) true t
| h::t -> loop (h::a) b t
loop [] false (str.ToCharArray() |> Array.toList)
Note that the character is given as char instead of a string.
Edit: Another way would be using regular expressions
open System.Text.RegularExpressions
let someOtherFunc c s =
let pat = Regex.Escape(c)
Regex.Replace(s, sprintf "(?<=%s.*)%s" pat pat, "")
Note that, in this case the character is given as string.
Edit 2:
let oneMoreFunc (c:char) (s:string) =
let pred = (<>) c
[ s |> Seq.takeWhile pred
seq [c]
s |> Seq.skipWhile pred |> Seq.filter pred ]
|> Seq.concat
|> System.String.Concat
When devising a function, think about gains from making its arguments generic. To pass state through the iteration, barring mutable variables, Seq.scan could be a weapon of choice. It folds into a tuple of new state and an option, then Seq.choose strips out the state and the unwanted elements.
In terms of functional building blocks, make it accept a predicate function 'a -> bool and let it return a function seq<'a> -> seq<'a>.
let filterDuplicates predicate =
Seq.scan (fun (flag, _) x ->
let p = predicate x in flag || p,
if flag && p then None else Some x ) (false, None)
>> Seq.choose snd
This can then easily reused to do other things as well, like 0 together with odd numbers.
filterDuplicates (fun i -> i % 2 = 0) [0..10]
// val it : seq<int> = seq [0; 1; 3; 5; ...]
Supplied with a call to the equality operator and fed into the constructor of System.String, you'll get near the signature you want, char -> seq<char> -> System.String.
let filterDuplicatesOfChar what s =
System.String(Array.ofSeq <| filterDuplicates ((=) what) s)
filterDuplicatesOfChar '.' "hi. my .name."
// val it : string = "hi. my name"

Spliting a list of strings in OCaml

I have a list as let a = ["q0,x";"q1,y"]; which is of type string list.
I want to make it as [("q0","x");("q1","y")]; which is a list of (string * string) tuples.
How do I do that??
You can use module Str and the function split :
let split =
List.map (fun str ->
match Str.split (Str.regexp ",") str with
| a :: b :: _ -> a, b
| _ -> assert false (* should not happen *))

How To Change List of Chars To String?

In F# I want to transform a list of chars into a string. Consider the following code:
let lChars = ['a';'b';'c']
If I simply do lChars.ToString, I get "['a';'b';'c']". I'm trying to get "abc". I realize I could probably do a List.reduce to get the effect I'm looking for but it seems like there should be some primitive built into the library to do this.
To give a little context to this, I'm doing some manipulation on individual characters in a string and when I'm done, I want to display the resulting string.
I've tried googling this and no joy that way. Do I need to just bite the bullet and build a List.reduce expression to do this transformation or is there some more elegant way to do this?
Have you tried
System.String.Concat(Array.ofList(lChars))
How many ways can you build a string in F#?
Here's another handful:
let chars = ['H';'e';'l';'l';'o';',';' ';'w';'o';'r';'l';'d';'!']
//Using an array builder
let hw1 = new string [|for c in chars -> c|]
//StringBuilder-Lisp-like approach
open System.Text
let hw2 =
string (List.fold (fun (sb:StringBuilder) (c:char) -> sb.Append(c))
(new StringBuilder())
chars)
//Continuation passing style
let hw3 =
let rec aux L k =
match L with
| [] -> k ""
| h::t -> aux t (fun rest -> k (string h + rest) )
aux chars id
Edit: timings may be interesting? I turned hw1..3 into functions and fed them a list of 500000 random characters:
hw1: 51ms
hw2: 16ms
hw3: er... long enough to grow a beard? I think it just ate all of my memory.
Didn't see this one here, so:
let stringFromCharList (cl : char list) =
String.concat "" <| List.map string cl
"" is just an empty string.
FSI output:
> stringFromCharList ['a'..'d'];;
val it : string = "abcd"
EDIT:
Didn't like this syntax coming back to this so here's a more canonically functional one:
['a'..'z'] |> List.map string |> List.reduce (+)
['a';'b';'c'] |> List.fold_left (fun acc c -> acc ^ (string c)) ""
Edited:
Here is yet another funny way to do your task:
type t =
| N
| S of string
static member Zero
with get() = N
static member (+) (a: t, b: t) =
match a,b with
| S a, S b -> S (a+b)
| N, _ -> b
| _, N -> a
let string_of_t = function
|N -> ""
|S s -> s
let t_of_char c = S (string c)
['a'; 'b'; 'c'] |> List.map t_of_char |> List.sum |> string_of_t
Sadly, just extending System.String with 'Zero' member does not allow to use List.sum with strings.
Edited (answer to Juilet):
Yes, you are right, left fold is slow. But i know more slow right fold :) :
#r "FSharp.PowerPack"
List.fold_right (String.make 1 >> (^)) ['a';'b';'c'] ""
and of course there is fast and simple:
new System.String(List.to_array ['1';'2';'3'])
And i used 'sprintf' seems to me easier:
let t = "Not what you might expect"
let r = [ for i in "aeiou" -> i]
let q = [for a in t do if not (List.exists (fun x -> x=a) r) then yield a]
let rec m = function [] -> "" | h::t -> (sprintf "%c" h) + (m t)
printfn "%A" (m q)
The following solution works for me:
let charList = ["H";"E";"L";"L";"O"]
let rec buildString list =
match list with
| [] -> ""
| head::tail -> head + (buildString tail)
let resultBuildString = buildString charList
[|'w'; 'i'; 'l'; 'l'|]
|> Array.map string
|> Array.reduce (+)
or as someone else posted:
System.String.Concat([|'w'; 'i'; 'l'; 'l'|])

Resources