Where my anagrams at?
Tags: kata, challenge, codewars, javascript
Published: 2019-12-03 19:11:15

## Task description

> Write a function that will find all the anagrams of a word from a list. You will be given two inputs a word and an array with words. You should return an array of all the anagrams or an empty array if there are none.

## Task solution

### Tests

```javascript
describe("anagram tests", () => {
  it("Should throw for invalid input", () => {
    expect(() => anagrams(1)).toThrow(/IllegalArgumentException/);
    expect(() => anagrams("test", 1)).toThrow(/IllegalArgumentException/);
    expect(() => anagrams("test", [1])).toThrow(/IllegalArgumentException/);
    expect(() => anagrams("test", ["test"], 1)).toThrow(/IllegalArgumentException/);
  });

  it("Should find all anagrams", () => {
    expect(anagrams("abba", ["aabb", "abcd", "bbaa", "dada"])).toEqual(["aabb", "bbaa"]);
    expect(anagrams("racer", ["crazer", "carer", "racar", "caers", "racer"])).toEqual(["carer", "racer"]);
    expect(anagrams("laser", ["lazing", "lazy",  "lacer"])).toEqual([]);

    function customSort(string) {
      return string.toLowerCase().split("").sort().reverse().join("");
    }
    expect(anagrams("Listen", ["Silent"], customSort)).toEqual(["Silent"]);
  });
});

describe("sortString tests", () => {
  it("Should return the input if not a string", () => {
    expect(sortString(1)).toBe(1);
  });

  it("Should return a sorted string as expected with valid input provided", () => {
    expect(sortString("acb")).toBe("abc");
  });
});
```

We begin with out invalid input tests, you will note that there is a 3rd parameter that users can add into the function outside of just the `word` to find and the `words` we wish the check if that `word` is an anagram of. This is because I am also allowing a custom sorting function to be applied if the user wishes. This is useful for if they rely on a third party framework and wish to use that implementation for example. Either way we test this out too to be sure it works as expected as we should do with all our code to the best of our abilities.

### Implementation

```javascript
function sortString(string) {
  if(typeof string !== "string") return string;
  return string.toLowerCase().split("").sort().join("");
}

function anagrams(word, words, sortingFunc = sortString) {
  if(typeof word !== "string") {
    throw new Error(`IllegalArgumentException: Parameter 1 must be a string. Received: ${typeof word}`);
  } else if(!Array.isArray(words)) {
    throw new Error(`IllegalArgumentException: Parameter 2 must be an array. Received: ${typeof words}`);
  } else if(!words.every(word => typeof word === "string")) {
    throw new Error(`IllegalArgumentException: Parameter 2 must be an array of strings but atlease one value within the array is not a string. Received: ${words}`);
  } else if(typeof sortingFunc !== "function") {
    throw new Error(`IllegalArgumentException: Parameter 3 must be a function. Received: ${typeof sortingFunc}`);
  }

  return words.filter(w => sortingFunc(w) === sortingFunc(word));
}
```

We write a helper function called `sortString`, this is to normalise each item into a string we can compare against the normalised `word` we are comparing it to, this helper will be the default implementation for parameter 3. Next we run our normal input validation tests and follow that with a simple `filter` call on the words array.

When filtering the `words` array, we want to return only the items which are anagrams of the `word` we are provided. In this way, we run the `sortingFunc` which, if no alternative is provided, will be our `sortString` function, over our current word (`w`) in the loop and our `word` we are searching for. If both match, we know it must be an anagram and thus it will be returned in the filtered output.

## Conclusions

This task was really easy but it is still something that's good for a quick brush up from time to time, for example: default parameter usage, working with data, etc. Foundational things and yet sometimes forgotten, either way, a simple solution to a simple problem was found. See you in the next one!