patternpythonModerate
Word Morph (changing one letter at a time)
Viewed 0 times
timeonewordletterchangingmorph
Problem
Below is my implementation of Word Morph solver in Python.
The challenge consists of transforming one word into another word by changing one letter at a time. Each word in the chain should be an English word (part of a dictionary). One should output all such chains of the minimal possible length. Examples:
Comments on algorithm (I only compare the leaves of the trees because it is more efficient) and general comments would be much appreciated.
Test cases have not been implemented properly, but they are not my primary concern for this code.
```
import enchant
from functools import total_ordering
from string import ascii_lowercase
@total_ordering
class WordWithPath:
dictEng = enchant.Dict("en_US")
def __init__(self, newWord, ancestor = None):
self.word = newWord
if ancestor == None:
self.path = []
else:
self.path = [ancestor.word] + ancestor.path
def __eq__(self, other):
if (other == None):
return False
return (self.word == other.word)
def __lt__(self, other):
return (self.word 0:
break
newRightLeaves = mergeManySortedLists([w.findNextWords() for w in rightLeaves])
rightAllNodes = mergeSortedLists(rightLeaves, rightAllNodes)
removeOverlaps(listToClean = newRightLeaves, listReference = rightAllNodes)
rightLeaves = newRightLeaves
overlaps = findOverlaps(leftLeaves, rightLeaves)
if len(overlaps)>0:
break
return [h1.concatenatePath(h2) for h1, h2 in overlaps]
if __name__ == '__main__':
allPaths = findChain("rough", "poach", 10)
for p in allPaths:
print p
allPaths = findChain("man", "spa", 10)
for p in allPaths:
print p
allPaths = findChain("tree", "fled", 10)
f
The challenge consists of transforming one word into another word by changing one letter at a time. Each word in the chain should be an English word (part of a dictionary). One should output all such chains of the minimal possible length. Examples:
'tree' to 'fled' chain is ['tree', 'free', 'flee', 'fled'], 'man' to 'spa' chains are ['man', 'may', 'say', 'spy', 'spa'] and ['man', 'men', 'sen', 'sea', 'spa'].Comments on algorithm (I only compare the leaves of the trees because it is more efficient) and general comments would be much appreciated.
Test cases have not been implemented properly, but they are not my primary concern for this code.
```
import enchant
from functools import total_ordering
from string import ascii_lowercase
@total_ordering
class WordWithPath:
dictEng = enchant.Dict("en_US")
def __init__(self, newWord, ancestor = None):
self.word = newWord
if ancestor == None:
self.path = []
else:
self.path = [ancestor.word] + ancestor.path
def __eq__(self, other):
if (other == None):
return False
return (self.word == other.word)
def __lt__(self, other):
return (self.word 0:
break
newRightLeaves = mergeManySortedLists([w.findNextWords() for w in rightLeaves])
rightAllNodes = mergeSortedLists(rightLeaves, rightAllNodes)
removeOverlaps(listToClean = newRightLeaves, listReference = rightAllNodes)
rightLeaves = newRightLeaves
overlaps = findOverlaps(leftLeaves, rightLeaves)
if len(overlaps)>0:
break
return [h1.concatenatePath(h2) for h1, h2 in overlaps]
if __name__ == '__main__':
allPaths = findChain("rough", "poach", 10)
for p in allPaths:
print p
allPaths = findChain("man", "spa", 10)
for p in allPaths:
print p
allPaths = findChain("tree", "fled", 10)
f
Solution
if ancestor == None:The part
== None is unnecessary and adds noise to your code. Since None is a falsey value, just checking for the opposite of it will result in True if it equal to None.Here is what I mean:
if not ancestor:i2 = i2+1Statements like this could be shortened to:
i2 += 1In
findChain, when you are adding errors to errors, split the errors up by newline so if the error message is viewed later, the different errors are more easily visible.if errors != '':
raise ValueError(errors)This can be simplified to
if errors:
raise ValueError(errors)Which just makes more sense as your are reading it ("If [there are] errors").
Don't do this:
result.append(list1[i1]); i1 = i1+1Semicolons are not very pythonic at all.
When you are brute-forcing words in
findNextWords, you could probably speed up your algorithm by following some English rules.One of the biggest and most known English rules is that every word must have a vowel.
Then, in
findNextWords, you can setup a simple conditional that checks if a word has at least one vowel. If so, then it is a valid word.Try to implement some other, lesser known English rules too. I'm sure you can find plenty here.
I might add more as I try to look more into the algorithm.
Code Snippets
if ancestor == None:if not ancestor:if errors != '':
raise ValueError(errors)if errors:
raise ValueError(errors)result.append(list1[i1]); i1 = i1+1Context
StackExchange Code Review Q#95906, answer score: 10
Revisions (0)
No revisions yet.