diff options
Diffstat (limited to 'raku/word-count')
-rw-r--r-- | raku/word-count/README.md | 54 | ||||
-rw-r--r-- | raku/word-count/WordCount.rakumod | 5 | ||||
-rw-r--r-- | raku/word-count/word-count.rakutest | 184 |
3 files changed, 243 insertions, 0 deletions
diff --git a/raku/word-count/README.md b/raku/word-count/README.md new file mode 100644 index 0000000..bf97113 --- /dev/null +++ b/raku/word-count/README.md @@ -0,0 +1,54 @@ +# Word Count + +Given a phrase, count the occurrences of each _word_ in that phrase. + +For the purposes of this exercise you can expect that a _word_ will always be one of: + +1. A _number_ composed of one or more ASCII digits (ie "0" or "1234") OR +2. A _simple word_ composed of one or more ASCII letters (ie "a" or "they") OR +3. A _contraction_ of two _simple words_ joined by a single apostrophe (ie "it's" or "they're") + +When counting words you can assume the following rules: + +1. The count is _case insensitive_ (ie "You", "you", and "YOU" are 3 uses of the same word) +2. The count is _unordered_; the tests will ignore how words and counts are ordered +3. Other than the apostrophe in a _contraction_ all forms of _punctuation_ are ignored +4. The words can be separated by _any_ form of whitespace (ie "\t", "\n", " ") + +For example, for the phrase `"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.` the count would be: + +```text +that's: 1 +the: 2 +password: 2 +123: 1 +cried: 1 +special: 1 +agent: 1 +so: 1 +i: 1 +fled: 1 +``` + +## Resources + +Remember to check out the Raku [documentation](https://docs.raku.org/) and +[resources](https://raku.org/resources/) pages for information, tips, and +examples if you get stuck. + +## Running the tests + +There is a test suite and module included with the exercise. +The test suite (a file with the extension `.rakutest`) will attempt to run routines +from the module (a file with the extension `.rakumod`). +Add/modify routines in the module so that the tests will pass! You can view the +test data by executing the command `raku --doc *.rakutest` (\* being the name of the +test suite), and run the test suite for the exercise by executing the command +`prove6 .` in the exercise directory. + +## Source + +This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour. + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/raku/word-count/WordCount.rakumod b/raku/word-count/WordCount.rakumod new file mode 100644 index 0000000..62bc1a5 --- /dev/null +++ b/raku/word-count/WordCount.rakumod @@ -0,0 +1,5 @@ +unit module WordCount; + +sub count-words (Str $sentence) is export { + $sentence.lc.comb(/\w+\'\w+|\w+/).Bag; +} diff --git a/raku/word-count/word-count.rakutest b/raku/word-count/word-count.rakutest new file mode 100644 index 0000000..45158aa --- /dev/null +++ b/raku/word-count/word-count.rakutest @@ -0,0 +1,184 @@ +#!/usr/bin/env raku +use Test; +use JSON::Fast; +use lib $?FILE.IO.dirname; +use WordCount; +plan 13; + +my @test-cases = from-json($=pod.pop.contents).List; +for @test-cases -> %case { + cmp-ok count-words(%case<input><sentence>), + '~~', %case<expected>.Bag, %case<description>; +} + +=head2 Test Cases +=begin code +[ + { + "description": "count one word", + "expected": { + "word": 1 + }, + "input": { + "sentence": "word" + }, + "property": "countWords" + }, + { + "description": "count one of each word", + "expected": { + "each": 1, + "of": 1, + "one": 1 + }, + "input": { + "sentence": "one of each" + }, + "property": "countWords" + }, + { + "description": "multiple occurrences of a word", + "expected": { + "blue": 1, + "fish": 4, + "one": 1, + "red": 1, + "two": 1 + }, + "input": { + "sentence": "one fish two fish red fish blue fish" + }, + "property": "countWords" + }, + { + "description": "handles cramped lists", + "expected": { + "one": 1, + "three": 1, + "two": 1 + }, + "input": { + "sentence": "one,two,three" + }, + "property": "countWords" + }, + { + "description": "handles expanded lists", + "expected": { + "one": 1, + "three": 1, + "two": 1 + }, + "input": { + "sentence": "one,\ntwo,\nthree" + }, + "property": "countWords" + }, + { + "description": "ignore punctuation", + "expected": { + "as": 1, + "car": 1, + "carpet": 1, + "java": 1, + "javascript": 1 + }, + "input": { + "sentence": "car: carpet as java: javascript!!&@$%^&" + }, + "property": "countWords" + }, + { + "description": "include numbers", + "expected": { + "1": 1, + "2": 1, + "testing": 2 + }, + "input": { + "sentence": "testing, 1, 2 testing" + }, + "property": "countWords" + }, + { + "description": "normalize case", + "expected": { + "go": 3, + "stop": 2 + }, + "input": { + "sentence": "go Go GO Stop stop" + }, + "property": "countWords" + }, + { + "description": "with apostrophes", + "expected": { + "cry": 1, + "don't": 2, + "first": 1, + "laugh": 1, + "then": 1 + }, + "input": { + "sentence": "First: don't laugh. Then: don't cry." + }, + "property": "countWords" + }, + { + "description": "with quotations", + "expected": { + "and": 1, + "between": 1, + "can't": 1, + "joe": 1, + "large": 2, + "tell": 1 + }, + "input": { + "sentence": "Joe can't tell between 'large' and large." + }, + "property": "countWords" + }, + { + "description": "substrings from the beginning", + "expected": { + "a": 1, + "and": 1, + "app": 1, + "apple": 1, + "between": 1, + "can't": 1, + "joe": 1, + "tell": 1 + }, + "input": { + "sentence": "Joe can't tell between app, apple and a." + }, + "property": "countWords" + }, + { + "description": "multiple spaces not detected as a word", + "expected": { + "multiple": 1, + "whitespaces": 1 + }, + "input": { + "sentence": " multiple whitespaces" + }, + "property": "countWords" + }, + { + "description": "alternating word separators not detected as a word", + "expected": { + "one": 1, + "three": 1, + "two": 1 + }, + "input": { + "sentence": ",\n,one,\n ,two \n 'three'" + }, + "property": "countWords" + } +] +=end code |