from itertools import count
mapping = {}
for letters, number in zip("bfpv cgjkqsxz dt l mn r".split(), count(1)):
mapping.update({letter:number for letter in letters})
def soundex(word):
word = word.lower()
first, rest = word[0], word[1:]
digits = []
digit = mapping.get(first)
for letter in rest:
next_digit = mapping.get(letter)
if next_digit is not None and next_digit != digit:
digits.append(next_digit)
if len(digits) == 3:
break
digit = next_digit
else:
digits.extend(0 for x in xrange(3 - len(digits)))
return first + "".join(map(str, digits))
assert map(soundex, "euler gauss hilbert knuth lloyd lukasiewicz".split()) \
== map(soundex, "ellery ghosh heilbronn kant ladd lissajous".split()) \
== "e460 g200 h416 k530 l300 l222".split()