Initial Commit
This commit is contained in:
21
go/anagram/README.md
Normal file
21
go/anagram/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Anagram
|
||||
|
||||
Write a program that, given a word and a list of possible anagrams, selects the correct sublist.
|
||||
|
||||
Given `"listen"` and a list of candidates like `"enlists" "google"
|
||||
"inlets" "banana"` the program should return a list containing
|
||||
`"inlets"`.
|
||||
|
||||
To run the tests simply run the command `go test` in the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||
flag:
|
||||
|
||||
go test -bench .
|
||||
|
||||
For more detailed info about the Go track see the [help
|
||||
page](http://exercism.io/languages/go).
|
||||
|
||||
## Source
|
||||
|
||||
Inspired by the Extreme Startup game [view source](https://github.com/rchatley/extreme_startup)
|
28
go/anagram/anagram.go
Normal file
28
go/anagram/anagram.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package anagram
|
||||
|
||||
import "strings"
|
||||
|
||||
// Detect returns all candidates that are anagrams of subject
|
||||
func Detect(subject string, candidates []string) []string {
|
||||
var ret []string
|
||||
for i := range candidates {
|
||||
if isAnagram(subject, candidates[i]) {
|
||||
ret = append(ret, strings.ToLower(candidates[i]))
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func isAnagram(s, c string) bool {
|
||||
s = strings.ToLower(s)
|
||||
c = strings.ToLower(c)
|
||||
if s == c || len(s) != len(c) {
|
||||
return false
|
||||
}
|
||||
for _, v := range strings.Split(s, "") {
|
||||
if strings.Count(s, v) != strings.Count(c, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
172
go/anagram/anagram_test.go
Normal file
172
go/anagram/anagram_test.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package anagram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testCases = []struct {
|
||||
subject string
|
||||
candidates []string
|
||||
expected []string
|
||||
description string
|
||||
}{
|
||||
{
|
||||
subject: "diaper",
|
||||
candidates: []string{
|
||||
"hello",
|
||||
"world",
|
||||
"zombies",
|
||||
"pants",
|
||||
},
|
||||
expected: []string{},
|
||||
description: "no matches",
|
||||
},
|
||||
{
|
||||
subject: "ant",
|
||||
candidates: []string{
|
||||
"tan",
|
||||
"stand",
|
||||
"at",
|
||||
},
|
||||
expected: []string{"tan"},
|
||||
description: "simple anagram",
|
||||
},
|
||||
{
|
||||
subject: "listen",
|
||||
candidates: []string{
|
||||
"enlists",
|
||||
"google",
|
||||
"inlets",
|
||||
"banana",
|
||||
},
|
||||
expected: []string{"inlets"},
|
||||
description: "another simple anagram",
|
||||
},
|
||||
{
|
||||
subject: "master",
|
||||
candidates: []string{
|
||||
"stream",
|
||||
"pigeon",
|
||||
"maters",
|
||||
},
|
||||
expected: []string{"maters", "stream"},
|
||||
description: "multiple anagrams",
|
||||
},
|
||||
{
|
||||
subject: "allergy",
|
||||
candidates: []string{
|
||||
"gallery",
|
||||
"ballerina",
|
||||
"regally",
|
||||
"clergy",
|
||||
"largely",
|
||||
"leading",
|
||||
},
|
||||
expected: []string{"gallery", "largely", "regally"},
|
||||
description: "multiple anagrams (again)",
|
||||
},
|
||||
{
|
||||
subject: "galea",
|
||||
candidates: []string{
|
||||
"eagle",
|
||||
},
|
||||
expected: []string{},
|
||||
description: "does not confuse different duplicates",
|
||||
},
|
||||
{
|
||||
subject: "corn",
|
||||
candidates: []string{
|
||||
"corn",
|
||||
"dark",
|
||||
"Corn",
|
||||
"rank",
|
||||
"CORN",
|
||||
"cron",
|
||||
"park",
|
||||
},
|
||||
expected: []string{"cron"},
|
||||
description: "identical word is not anagram",
|
||||
},
|
||||
{
|
||||
subject: "mass",
|
||||
candidates: []string{
|
||||
"last",
|
||||
},
|
||||
expected: []string{},
|
||||
description: "eliminate anagrams with same checksum",
|
||||
},
|
||||
{
|
||||
subject: "good",
|
||||
candidates: []string{
|
||||
"dog",
|
||||
"goody",
|
||||
},
|
||||
expected: []string{},
|
||||
description: "eliminate anagram subsets",
|
||||
},
|
||||
{
|
||||
subject: "Orchestra",
|
||||
candidates: []string{
|
||||
"cashregiser",
|
||||
"carthorse",
|
||||
"radishes",
|
||||
},
|
||||
expected: []string{"carthorse"},
|
||||
description: "subjects are case insensitive",
|
||||
},
|
||||
{
|
||||
subject: "orchestra",
|
||||
candidates: []string{
|
||||
"cashregiser",
|
||||
"Carthorse",
|
||||
"radishes",
|
||||
},
|
||||
expected: []string{"carthorse"},
|
||||
description: "candidates are case insensitive",
|
||||
},
|
||||
}
|
||||
|
||||
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 %v
|
||||
Expected %v
|
||||
Got %v
|
||||
`
|
||||
t.Fatalf(msg, tt.description, tt.subject, tt.candidates, tt.expected, actual)
|
||||
} else {
|
||||
t.Logf("PASS: %s", tt.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDetectAnagrams(b *testing.B) {
|
||||
|
||||
b.StopTimer()
|
||||
|
||||
for _, tt := range testCases {
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
Detect(tt.subject, tt.candidates)
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user