ðŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io ðŸŽ‰

# hyphenrf's solution

## to Word Count in the OCaml Track

Published at Jul 08 2020 · 0 comments
Instructions
Test suite
Solution

Given a phrase, count the occurrences of each word in that phrase.

For example for the input `"olly olly in come free"`

``````olly: 2
in: 1
come: 1
free: 1
``````

## Getting Started

1. For library documentation, follow Useful OCaml resources.

## Running Tests

A `Makefile` is provided with a default target to compile your solution and run the tests. At the command line, type:

``````make
``````

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

## Feedback, Issues, Pull Requests

The exercism/ocaml repository on GitHub is the home for all of the Ocaml exercises.

If you have feedback about an exercise, or want to help implementing a new one, head over there and create an issue or submit a PR. We welcome new contributors!

## Source

This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour.

### test.ml

``````(* word-count - 1.3.0 *)
open Base
open OUnit2
open Word_count

let ae exp got _test_ctxt =
let cmp = Map.equal (=) in
let sexp_of_map = Map.sexp_of_m__t (module String) in
let printer m = sexp_of_map Int.sexp_of_t m |> Sexp.to_string_hum ~indent:1 in
assert_equal ((Map.of_alist_exn (module String)) exp) got ~cmp ~printer

let tests = [
"count one word" >::
ae [("word", 1)]
(word_count "word");
"count one of each word" >::
ae [("one", 1); ("of", 1); ("each", 1)]
(word_count "one of each");
"multiple occurrences of a word" >::
ae [("one", 1); ("fish", 4); ("two", 1); ("red", 1); ("blue", 1)]
(word_count "one fish two fish red fish blue fish");
"handles cramped lists" >::
ae [("one", 1); ("two", 1); ("three", 1)]
(word_count "one,two,three");
"handles expanded lists" >::
ae [("one", 1); ("two", 1); ("three", 1)]
(word_count "one,\ntwo,\nthree");
"ignore punctuation" >::
ae [("car", 1); ("carpet", 1); ("as", 1); ("java", 1); ("javascript", 1)]
(word_count "car: carpet as java: javascript!!&@\$%^&");
"include numbers" >::
ae [("testing", 2); ("1", 1); ("2", 1)]
(word_count "testing, 1, 2 testing");
"normalize case" >::
ae [("go", 3); ("stop", 2)]
(word_count "go Go GO Stop stop");
"with apostrophes" >::
ae [("first", 1); ("don't", 2); ("laugh", 1); ("then", 1); ("cry", 1)]
(word_count "First: don't laugh. Then: don't cry.");
"with quotations" >::
ae [("joe", 1); ("can't", 1); ("tell", 1); ("between", 1); ("large", 2); ("and", 1)]
(word_count "Joe can't tell between 'large' and large.");
"multiple spaces not detected as a word" >::
ae [("multiple", 1); ("whitespaces", 1)]
(word_count " multiple   whitespaces");
"alternating word separators not detected as a word" >::
ae [("one", 1); ("two", 1); ("three", 1)]
(word_count ",\n,one,\n ,two \n 'three'");
]

let () =
run_test_tt_main ("word_count tests" >::: tests)``````
``````open Base

let sym_strip s = match
String.strip s ~drop:(fun c -> not @@ Char.is_alphanum c)
with | "" -> None
| cs -> Some cs

let bump = Map.update ~f:(function None -> 1 | Some n -> 1+n)

let word_count s = s
|> String.lowercase
|> String.split_on_chars ~on:['\n';' ';',']
|> List.filter_map ~f:sym_strip
|> List.fold ~f:bump ~init:(Map.empty (module String))``````