Raga Man - Scala Anagram Finder
Anagram Finder
There is only so far you can go with Hello World, so my next task was to solve a problem a friend of mine was given in an interview. How would you write an anagram solver in scala.
Don't expect a nice pithy solution, this will be a journey trying out various constructs along the way. I will be writing tests for everything, but things may get messy. For a start - I am too lazy/eager to start a new project so I am just hacking it on to my hello world app. Once I have a working tool I will look at refactoring and creating some sort of restful api.
The rules:
I'm unsure what constraints the interview question set, but mine are as follows:
- Given a word and a list of valid words, find all potential anagrams of that word.
- Any potential anagram must consist of one or more valid words that are, obviously, not the same word.
The code.
I have added the source code to my github account, feel free to check it out. I will include code snippets inline, but if you want to know what goes where in the file system, please browse the various tags I have created an linked to github.
So, to get started - I created a class called AnagramFinder and wrote a spec for that class.
import org.specs2.Specification
class AnagramFinderSpec extends Specification { def is = s2"""
I can get an instance of an AnagramFinder
valid instance $anagramFinder1
should contain the word that we are looking for anagrams of $hasword
I can check that a word is entirely contained within another word
hell is contained in hello $hello_contains_hell
help is not contained in hello $hello_does_not_contains_help
"""
def anagramFinder1 = new AnagramFinder("hello") must beAnInstanceOf[AnagramFinder]
def hasword = new AnagramFinder("hello").word must be_==("hello")
def hello_contains_hell = new AnagramFinder("hello").contains("hell") must be_==(true)
def hello_does_not_contains_help = new AnagramFinder("hello").contains("help") must be_==(false)
}
The code required to pass these tests is here:
class AnagramFinder(myword: String ) {
var word: String = myword
def contains(str: String) = {
word.contains(str)
}
}
so far so good, but nowhere near complete, for instance this wont work when asked if hello contains "leo", which it clearly does.
So lets add a test
leo is contained in hello $hello_contains_leo
...
def hello_contains_leo = new AnagramFinder("hello").contains("leo") must be_==(true)
see here for code
Now this doesn't pass
[info] AnagramFinderSpec
[info] I can get an instance of an AnagramFinder
[info] + valid instance
[info] + should contain the word that we are looking for anagrams of
[info]
[info] I can check that a word is entirely contained within another word
[info] + hell is contained in hello
[info] + help is not contained in hello
[error] x leo is contained in hello
[error] the value is not equal to 'true' (AnagramFinderSpec.scala:17)
So I tried a couple of ways of doing this, and to cut a long story short, word.toList.contains(str.toList)
didn't work; and word.toCharArray.contains(str.toCharArray)
didn't either
but thanks to StackOverflow I found this sugestion that did.
class AnagramFinder(myword: String ) {
var word: String = myword
def contains(str: String) = {
str.toSet.subsetOf(word.toSet)
}
}
running my tests again:
[info] AnagramFinderSpec
[info] I can get an instance of an AnagramFinder
[info] + valid instance
[info] + should contain the word that we are looking for anagrams of
[info]
[info] I can check that a word is entirely contained within another word
[info] + hell is contained in hello
[info] + help is not contained in hello
[info] + leo is contained in hello
[info]
[info] Total for specification AnagramFinderSpec
[info] Finished in 39 ms
[info] 5 examples, 0 failure, 0 error
This is the point where I start to see the elegance of scala as a language