Avatar of artemkorsakov

artemkorsakov's solution

to Anagram in the Go Track

Published at Feb 21 2019 · 0 comments
Instructions
Test suite
Solution

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".

Running the tests

To run the tests run the command go test from within the exercise directory.

If the test suite contains benchmarks, you can run these with the --bench and --benchmem flags:

go test -v --bench . --benchmem

Keep in mind that each reviewer will run benchmarks on a different machine, with different specs, so the results from these benchmark tests may vary.

Further information

For more detailed information about the Go track, including how to get help if you're having trouble, please visit the exercism.io Go language page.

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.

anagram_test.go

package anagram

import (
	"fmt"
	"sort"
	"testing"
)

func equal(a []string, b []string) bool {
	if len(b) != len(a) {
		return false
	}

	sort.Strings(a)
	sort.Strings(b)
	return fmt.Sprintf("%v", a) == fmt.Sprintf("%v", b)
}

func TestDetectAnagrams(t *testing.T) {
	for _, tt := range testCases {
		actual := Detect(tt.subject, tt.candidates)
		if !equal(tt.expected, actual) {
			msg := `FAIL: %s
	Subject %s
	Candidates %q
	Expected %q
	Got %q
				`
			t.Fatalf(msg, tt.description, tt.subject, tt.candidates, tt.expected, actual)
		} else {
			t.Logf("PASS: %s", tt.description)
		}
	}
}

func BenchmarkDetectAnagrams(b *testing.B) {

	for i := 0; i < b.N; i++ {

		for _, tt := range testCases {
			Detect(tt.subject, tt.candidates)
		}

	}

}

cases_test.go

package anagram

// Source: exercism/problem-specifications
// Commit: baaf092 anagram: words are not anagrams of themselves
// Problem Specifications Version: 1.4.0

var testCases = []struct {
	description string
	subject     string
	candidates  []string
	expected    []string
}{
	{
		description: "no matches",
		subject:     "diaper",
		candidates: []string{
			"hello",
			"world",
			"zombies",
			"pants"},
		expected: []string{},
	},
	{
		description: "detects two anagrams",
		subject:     "master",
		candidates: []string{
			"stream",
			"pigeon",
			"maters"},
		expected: []string{
			"stream",
			"maters"},
	},
	{
		description: "does not detect anagram subsets",
		subject:     "good",
		candidates: []string{
			"dog",
			"goody"},
		expected: []string{},
	},
	{
		description: "detects anagram",
		subject:     "listen",
		candidates: []string{
			"enlists",
			"google",
			"inlets",
			"banana"},
		expected: []string{
			"inlets"},
	},
	{
		description: "detects three anagrams",
		subject:     "allergy",
		candidates: []string{
			"gallery",
			"ballerina",
			"regally",
			"clergy",
			"largely",
			"leading"},
		expected: []string{
			"gallery",
			"regally",
			"largely"},
	},
	{
		description: "does not detect non-anagrams with identical checksum",
		subject:     "mass",
		candidates: []string{
			"last"},
		expected: []string{},
	},
	{
		description: "detects anagrams case-insensitively",
		subject:     "Orchestra",
		candidates: []string{
			"cashregister",
			"Carthorse",
			"radishes"},
		expected: []string{
			"Carthorse"},
	},
	{
		description: "detects anagrams using case-insensitive subject",
		subject:     "Orchestra",
		candidates: []string{
			"cashregister",
			"carthorse",
			"radishes"},
		expected: []string{
			"carthorse"},
	},
	{
		description: "detects anagrams using case-insensitive possible matches",
		subject:     "orchestra",
		candidates: []string{
			"cashregister",
			"Carthorse",
			"radishes"},
		expected: []string{
			"Carthorse"},
	},
	{
		description: "does not detect a anagram if the original word is repeated",
		subject:     "go",
		candidates: []string{
			"go Go GO"},
		expected: []string{},
	},
	{
		description: "anagrams must use all letters exactly once",
		subject:     "tapper",
		candidates: []string{
			"patter"},
		expected: []string{},
	},
	{
		description: "words are not anagrams of themselves (case-insensitive)",
		subject:     "BANANA",
		candidates: []string{
			"BANANA",
			"Banana",
			"banana"},
		expected: []string{},
	},
}
package anagram

import (
	"strings"
)

const alphabet = "abcdefghijklmnopqrstuvwxyz"

// Detect returns anagrams of the given word.
func Detect(subject string, candidates []string) []string {
	result := make([]string, 0)
	for _, candidate := range candidates {
		if IsAnagram(subject, candidate) {
			result = append(result, candidate)
		}
	}
	return result
}

// IsAnagram checks whether words are anagrams.
func IsAnagram(first string, second string) bool {
	if len(first) != len(second) {
		return false
	}

	firstLower := strings.ToLower(first)
	secondLower := strings.ToLower(second)
	if firstLower == secondLower {
		return false
	}

	for _, c := range alphabet {
		if strings.Count(firstLower, string(c)) != strings.Count(secondLower, string(c)) {
			return false
		}
	}
	return true
}

Community comments

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

What can you learn from this solution?

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?