Anagrams with python

I was asked to write a bit of python code to find anagrams. The code consists of a class with one method and a unittest.TestCase companion. The anagram class takes a list of words and performs some crude checks to make sure the class word list is not empty. Passing a word to the get_anagrams will return a set([]) of all anagrams for that word. For example, passing in ‘cat’ will return set([‘act’, ‘cat’]).

The word list used here is found in /usr/share/dict/words, this should be ok for mac and linux users, anyone using windows will have to provide a word list and change the tests.

#!/usr/bin/env python

import itertools
import unittest
import types
import os

class Anagram( object ):
    def __init__(self, words):
        """
        Create an array containing words supplied in <words>.
        Raises errors if 1) words isn't a list type
                         2) words turns out to be empty or contains only non-StringType(s)
        """
        if not isinstance(words, types.ListType):
            raise TypeError("Anagram takes a list of strings")
        else:
            self.words = [ i for i in words if isinstance( i, types.StringType )]

            if len(self.words) == 0:
                raise ValueError("Empty word list")
            
    def get_anagrams(self, word):
        """
        Given a word returns a list of anagrams for <word>
        Example: x.get_anagrams('cat') would return set(['act', 'cat'])
        """
        if not isinstance(word, types.StringType):
            raise TypeError("get_anagrams takes a StringType")

        #Get a list of words from self.words that are the same length as word
        filtered_words = set([i for i in self.words if len(i) == len(word)])

        #create a list of all possible combintations of word - create tuple of chars
        #then join the ('d', 'a', 'n') to form  string - 'dan'
        word_permutations = set([ ''.join(w) for w in itertools.permutations( word )])

        #use set.intersection to find all 'real' words, specifically those found in <words>
        return  word_permutations.intersection(filtered_words)

class TestAnagram( unittest.TestCase ):
    def test_constructor(self):
        self.assertRaises(TypeError,  Anagram, 1)
        self.assertRaises(TypeError,  Anagram, "cat")        
        self.assertRaises(TypeError,  Anagram, ())
        self.assertRaises(ValueError, Anagram, [1,2])        
    
    def setUp(self):
        filename   = '/usr/share/dict/words'
        if not os.path.isfile(filename):
            raise IOError( "Sample word file does not exist" )
    
        self.words = [i.strip() for i in open(filename).readlines()]
        self.ana   = Anagram(self.words)

    def test_get_anagrams(self):
        cat_like = self.ana.get_anagrams('cat')
        python_no_mates   = self.ana.get_anagrams('python')
        self.assertEqual( cat_like, set(['act','cat']) )
        self.assertEqual( python_no_mates,  set([]) )
        
    def test_argument_get_anagrams(self):
        self.assertRaises(TypeError, self.ana.get_anagrams, 1)
        self.assertRaises(TypeError, self.ana.get_anagrams, [1])
        self.assertRaises(TypeError, self.ana.get_anagrams, {})
        
if __name__ == '__main__':
    unittest.main()

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s