🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉
Avatar of ggwadera

ggwadera's solution

to Anagram in the Java Track

Published at Jun 30 2020 · 0 comments
Instructions
Test suite
Solution

Note:

This exercise has changed since this solution was written.

Given a word and a list of possible anagrams, select the correct sublist.

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

Setup

Go through the setup instructions for Java to install the necessary dependencies:

https://exercism.io/tracks/java/installation

Running the tests

You can run all the tests for an exercise by entering the following in your terminal:

$ gradle test

In the test suites all tests but the first have been skipped.

Once you get a test passing, you can enable the next one by removing the @Ignore("Remove to run test") annotation.

Source

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

Submitting Incomplete Solutions

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

AnagramTest.java

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Ignore;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collections;

public class AnagramTest {


    @Test
    public void testNoMatches() {
        Anagram detector = new Anagram("diaper");

        assertThat(
            detector.match(
                Arrays.asList("hello", "world", "zombies", "pants")))
            .isEmpty();
    }

    @Ignore("Remove to run test")
    @Test
    public void testDetectMultipleAnagrams() {
        Anagram detector = new Anagram("master");

        assertThat(detector.match(Arrays.asList("stream", "pigeon", "maters")))
            .containsExactlyInAnyOrder​("maters", "stream");
    }

    @Ignore("Remove to run test")
    @Test
    public void testEliminateAnagramSubsets() {
        Anagram detector = new Anagram("good");

        assertThat(detector.match(Arrays.asList("dog", "goody"))).isEmpty();
    }

    @Ignore("Remove to run test")
    @Test
    public void testDetectLongerAnagram() {
        Anagram detector = new Anagram("listen");

        assertThat(
            detector.match(
                Arrays.asList("enlists", "google", "inlets", "banana")))
            .containsExactlyInAnyOrder​("inlets");
    }

    @Ignore("Remove to run test")
    @Test
    public void testDetectMultipleAnagramsForLongerWord() {
        Anagram detector = new Anagram("allergy");
        assertThat(
            detector.match(
                Arrays.asList(
                    "gallery",
                    "ballerina",
                    "regally",
                    "clergy",
                    "largely",
                    "leading")))
            .containsExactlyInAnyOrder​("gallery", "regally", "largely");
    }

    @Ignore("Remove to run test")
    @Test
    public void testDetectsMultipleAnagramsWithDifferentCase() {
        Anagram detector = new Anagram("nose");

        assertThat(detector.match(Arrays.asList("Eons", "ONES")))
            .containsExactlyInAnyOrder​("Eons", "ONES");
    }

    @Ignore("Remove to run test")
    @Test
    public void testEliminateAnagramsWithSameChecksum() {
        Anagram detector = new Anagram("mass");

        assertThat(detector.match(Collections.singletonList("last")))
            .isEmpty();
    }

    @Ignore("Remove to run test")
    @Test
    public void testCaseInsensitiveWhenBothAnagramAndSubjectStartWithUpperCaseLetter() {
        Anagram detector = new Anagram("Orchestra");

        assertThat(
            detector.match(
                Arrays.asList("cashregister", "Carthorse", "radishes")))
            .containsExactlyInAnyOrder​("Carthorse");
    }

    @Ignore("Remove to run test")
    @Test
    public void testCaseInsensitiveWhenSubjectStartsWithUpperCaseLetter() {
        Anagram detector = new Anagram("Orchestra");

        assertThat(
            detector.match(
                Arrays.asList("cashregister", "carthorse", "radishes")))
            .containsExactlyInAnyOrder​("carthorse");
    }

    @Ignore("Remove to run test")
    @Test
    public void testCaseInsensitiveWhenAnagramStartsWithUpperCaseLetter() {
        Anagram detector = new Anagram("orchestra");

        assertThat(
            detector.match(
                Arrays.asList("cashregister", "Carthorse", "radishes")))
            .containsExactlyInAnyOrder​("Carthorse");
    }

    @Ignore("Remove to run test")
    @Test
    public void testIdenticalWordRepeatedIsNotAnagram() {
        Anagram detector = new Anagram("go");

        assertThat(detector.match(Collections.singletonList("go Go GO")))
            .isEmpty();
    }

    @Ignore("Remove to run test")
    @Test
    public void testAnagramMustUseAllLettersExactlyOnce() {
        Anagram detector = new Anagram("tapper");

        assertThat(detector.match(Collections.singletonList("patter")))
            .isEmpty();
    }

    @Ignore("Remove to run test")
    @Test
    public void testWordsAreNotAnagramsOfThemselvesCaseInsensitive() {
        Anagram detector = new Anagram("BANANA");

        assertThat(detector.match(Arrays.asList("BANANA", "Banana", "banana")))
            .isEmpty();
    }

    @Ignore("Remove to run test")
    @Test
    public void testWordsOtherThanThemselvesCanBeAnagrams() {
        Anagram detector = new Anagram("LISTEN");

        assertThat(detector.match(Arrays.asList("Listen", "Silent", "LISTEN")))
            .containsExactlyInAnyOrder​("Silent");
    }

}
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Anagram {

    private String word;
    private Map<Character, Long> frequencyMap;

    public Anagram(String word) {
        this.word = word.toLowerCase();
        frequencyMap = getCharsFrequency(this.word);
    }

    public List<String> match(List<String> words) {
        List<String> matches = new ArrayList<>();
        for (String word : words) {
            if (isAnagram(word.toLowerCase())) {
                matches.add(word);
            }
        }
        return matches;
    }

    private boolean isAnagram(String word) {
        if (word.length() != this.word.length()) {
            return false;
        } else if (word.equals(this.word)) {
            return false;
        }
        Map<Character, Long> frequencyMap = getCharsFrequency(word);

        for (char c : frequencyMap.keySet()) {
            if (!frequencyMap.get(c).equals(this.frequencyMap.get(c))) {
                return false;
            }
        }

        return true;
    }

    private Map<Character, Long> getCharsFrequency(String word) {
        return word.chars()
        .mapToObj(c -> (char) c)
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    }
}

Community comments

Find this solution interesting? Ask the author a question to learn more.

ggwadera's Reflection

Solution using chars frequency map