HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

CarTalk's Homophones Puzzler: A Programmatic Solution

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
cartalkhomophonesprogrammaticsolutionpuzzler

Problem

The puzzler:


This was sent in by a fellow named Dan O'Leary. He came upon a common
one-syllable, five-letter word recently that has the following unique
property. When you remove the first letter, the remaining letters form
a homophone of the original word, that is a word that sounds exactly
the same. Replace the first letter, that is, put it back and remove
the second letter and the result is yet another homophone of the
original word. And the question is, what's the word?


Now I'm going to give you an example that doesn't work. Let's look at
the five-letter word, 'wrack.' W-R-A-C-K, you know like to 'wrack with
pain.' If I remove the first letter, I am left with a four-letter
word, 'R-A-C-K.' As in, 'Holy cow, did you see the rack on that buck!
It must have been a nine-pointer!' It's a perfect homophone. If you
put the 'w' back, and remove the 'r,' instead, you're left with the
word, 'wack,' which is a real word, it's just not a homophone of the
other two words.

I've used CMU Pronouncing Dictionary and modified it (manually) to keep alphabetical strings only.

My code:

```
def read_dict(file_path):
"""Reads 'CMU Pronouncing Dictionary' text file.

returns: dict mapping from a word to a string describing
its pronounciation

file_path: str
"""
fin = open(file_path)
pron_dict = {}

for line in fin:
index = line.find(' ') # e.g. "AA EY2 EY1"
word = line[:index]
pron = line[index+2:]
pron_dict[word] = pron

return pron_dict

def are_homophones(pron_dict, word1, word2, word3):
"""Returns whether 3 words are homophones.

pron_dict: dict
"""

for word in [word1, word2, word3]:
if not word in pron_dict:
return False

return pron_dict[word1] == pron_dict[word2] == pron_dict[word3]

def find_homophones_words(pron_dict):
"""Returns a list of words, where:

* word
* word with the first item omitted

Solution

There's an efficiency improvement you could make to are_homophones: As is, you check that all three words are in pron_dict before checking that they're the same. However, it's better practice to catch errors using try blocks rather than trying to prevent them from happening (see this Stack Overflow post). A cleaner/faster way way to write this would be

def are_homophones(pron_dict, word1, word2, word3):
    try:
        return pron_dict[word1] == pron_dict[word2] == pron_dict[word3]
    except KeyError:
        return False


It's also good practice to use with blocks to open files so that Python automatically handles closing the file. With this change, read_dict becomes

def read_dict(file_path):
    pron_dict = {}

    with open(file_path) as fin:
        for line in fin:
            index = line.find(' ')  # e.g. "AA  EY2 EY1"
            word = line[:index] 
            pron = line[index+2:]
            pron_dict[word] = pron

    return pron_dict

Code Snippets

def are_homophones(pron_dict, word1, word2, word3):
    try:
        return pron_dict[word1] == pron_dict[word2] == pron_dict[word3]
    except KeyError:
        return False
def read_dict(file_path):
    pron_dict = {}

    with open(file_path) as fin:
        for line in fin:
            index = line.find(' ')  # e.g. "AA  EY2 EY1"
            word = line[:index] 
            pron = line[index+2:]
            pron_dict[word] = pron

    return pron_dict

Context

StackExchange Code Review Q#139395, answer score: 7

Revisions (0)

No revisions yet.