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

tkovs's solution

to Anagram in the ReasonML Track

Published at Oct 24 2020 · 0 comments
Instructions
Test suite
Solution

An anagram is a rearrangement of letters to form a new word. Given a word and a list of candidates, select the sublist of anagrams of the given word.

Given `"listen"` and a list of candidates like `"enlists" "google" "inlets" "banana"` the program should return a list containing `"inlets"`.

Source

Inspired by the Extreme Startup game https://github.com/rchatley/extreme_startup

Building and testing

You will need the node package manager (npm) installed - download from here There is one time setup for each exercise, which may take a few minutes:

``````npm install
``````

Open two shells, and in the first, start the build process.

``````npm start
``````

In the second, start the tests running.

``````npm test
``````

As you edit the code, the two processes will continually rebuild and rerun the tests.

Anagram_test.re

``````open Jest;
open Expect;
open Anagram;

describe("Anagram", () => {
test("no matches", () =>
expect(anagrams("diaper", ["hello", "world", "zombies", "pants"])) |> toEqual([])
);
test("detects two anagrams", () =>
expect(anagrams("master", ["stream", "pigeon", "maters"])) |> toEqual(["stream", "maters"])
);
test("does not detect anagram subsets", () =>
expect(anagrams("good", ["dog", "goody"]))  |> toEqual([])
);
test("detects anagram", () =>
expect(anagrams("listen", ["enlists", "google", "inlets", "banana"]))  |> toEqual(["inlets"])
);
test("detects three anagrams", () =>
expect(anagrams("allergy", ["gallery", "ballerina", "regally", "clergy", "largely", "leading"]))  |> toEqual(["gallery", "regally", "largely"])
);
test("detects multiple anagrams with different case", () =>
expect(anagrams("nose", ["Eons", "ONES"]))  |> toEqual(["Eons", "ONES"])
);
test("does not detect non-anagrams with identical checksum", () =>
expect(anagrams("mass", ["last"]))  |> toEqual([])
);
test("detects anagrams case-insensitively", () =>
expect(anagrams("Orchestra", ["cashregister", "Carthorse", "radishes"]))  |> toEqual(["Carthorse"])
);
test("detects anagrams using case-insensitive subject", () =>
expect(anagrams("Orchestra", ["cashregister", "carthorse", "radishes"])) |> toEqual(["carthorse"])
);
test("detects anagrams using case-insensitive possible matches", () =>
expect(anagrams("orchestra", ["cashregister", "Carthorse", "radishes"])) |> toEqual(["Carthorse"])
);
test("does not detect a anagram if the original word is repeated", () =>
expect(anagrams("go", ["go Go GO"])) |> toEqual([])
);
test("anagrams must use all letters exactly once", () =>
expect(anagrams("tapper", ["patter"])) |> toEqual([])
);
test("words are not anagrams of themselves (case-insensitive)", () =>
expect(anagrams("BANANA", ["BANANA", "Banana", "banana"])) |> toEqual([])
);
test("words other than themselves can be anagrams", () =>
expect(anagrams("LISTEN", ["Listen", "Silent", "LISTEN"])) |> toEqual(["Silent"])
);
})``````
``````let rec removeLetter = (word: string, letter: string): string => {
open Js.String2

let head = charAt(word, 0)
let tail = substringToEnd(word, ~from=1)

if (head == letter) {
tail
} else {
if (length(tail) == 0) {
} else {
head ++ removeLetter(tail, letter)
}
}
}

let rec isAnagramAux = (word1, word2) => {
open Js.String2

let word1length = length(word1)
let word2length = length(word2)

if (word1length != word2length) {
false
} else if (word1length == 0) {
true
} else {
let head = charAt(word1, 0)
let tail = substringToEnd(word1, ~from=1)
}
}

let isAnagram = (word1, word2) => {
open Js.String2

let uppercaseWord1 = toUpperCase(word1)
let uppercaseWord2 = toUpperCase(word2)
uppercaseWord1 != uppercaseWord2 && isAnagramAux(uppercaseWord1, uppercaseWord2)
}

let anagrams = (word, candidates) =>
List.filter(candidate => isAnagram(candidate, word), candidates)``````