# A History Lesson

Soundex is an interesting phonetic algorithm developed nearly 100 years ago for indexing names as they are pronounced in English. The goal is for homophones to be encoded to the same representation so that they can be matched despite minor differences in spelling.

Reference: https://en.wikipedia.org/wiki/Soundex



# Preface

I first read about Soundex over 30 years ago. At the time it seemed to me almost  like  A.I. that you could just type in somebody's name the way it sounded and there was still a pretty good chance it could match the correct person record. That was about the same year as the first "Terminator" movie so it was easy for me to put 2 and 2 together and conclude that Arnie must have had some kind of futuristic Soundex chip in his titanium skull helping him to locate ```Serah Coner```... or was it ```Sarh Connor```... or maybe ```Sayra Cunnarr```...

:-)



# Task

In this Kata you will encode strings using a Soundex variation called "American Soundex" using the following (case insensitive) steps:

* Save the first letter. Remove all occurrences of ```h``` and ```w``` except first letter.
* Replace all consonants (include the first letter) with digits as follows:
 * ```b```, ```f```, ```p```, ```v``` = 1
 * ```c```, ```g```, ```j```, ```k```, ```q```, ```s```, ```x```, ```z``` = 2
 * ```d```, ```t``` = 3
 * ```l``` = 4
 * ```m```, ```n``` = 5
 * ```r``` = 6
* Replace all adjacent same digits with one digit.
* Remove all occurrences of ```a```, ```e```, ```i```, ```o```, ```u```, ```y``` except first letter.
* If first symbol is a digit replace it with letter saved on step 1.
* Append 3 zeros if result contains less than 3 digits. Remove all except first letter and 3 digits after it

## Input

A space separated string of one or more names. E.g.

```Sarah Connor```

## Output

Space separated string of equivalent Soundex codes (the first character of each code must be uppercase). E.g.

```S600 C560```

Difficulty: introductory

Starter code:

def soundex(name):
	

Solutions:
import re

REPLACMENTS  = ["BFPV", "CGJKQSXZ", "DT","L","MN","R"]
ER1, ER2     = "HW", "AEIOUY"

TABLE_ERASE1 = str.maketrans("", "", ER1)
TABLE_NUMS   = str.maketrans( ''.join(REPLACMENTS), ''.join( str(n)*len(elt) for n,elt in enumerate(REPLACMENTS, 1)) )
TABLE_ERASE2 = str.maketrans("", "", ER2)


def formatSoundex(w):
    s = w[0]*(w[0] in ER1+ER2) +  re.sub(r'(\d)\1*', r'\1', w.translate(TABLE_ERASE1).translate(TABLE_NUMS)).translate(TABLE_ERASE2)
    return ((w[0] if s[0].isdigit() else s[0]) + s[1:] + "000")[:4]

def soundex(name):
    return ' '.join(formatSoundex(w.upper()) for w in name.split(" "))

import re
def soundex(name):
    newNameLis = [x[0].upper()+x.lower() for x in name.split(" ")]
    newNameLis = [x[0] + x[1]+x[2:].translate(str.maketrans('', '','hw')) for x in newNameLis]
    newNameLis = [x[0] + x[1:].translate(str.maketrans('bfpvcgjkqsxzdtlmnr', '111122222222334556','')) for x in newNameLis]
    newNameLis = [x[0] + re.sub(r'(\d)\1*', r'\1',x[1:]) for x in newNameLis]
    newNameLis = [x[0] + x[1]+x[2:].translate(str.maketrans('', '','aeiouy')) for x in newNameLis]
    newNameLis = [x[0] + "".join([i for i in x[2:] if i.isdigit()]) for x in newNameLis]
    return " ".join([(x+'000')[:4] for x in newNameLis])



T = str.maketrans('BFPVCGJKQSXZDTLMNR','111122222222334556')
V = str.maketrans({v:None for v in 'AEIOUY'})

def soundex(name):
    return ' '.join(wordex(w) for w in name.upper().split())
    
def wordex(word):
    w = (word[0] + word[1:].replace('W', '').replace('H', '')).translate(T)
    for c in '123456':
        while c + c in w: w = w.replace(c + c, c)
            
    return ((word[0] if w[0].isdigit() else w[0]) + w[1:].translate(V) +'000')[:4]

from itertools import groupby

tr = [  (0,), ('b','f','p','v'), ('c','g','j','k','q','s','x','z'), ('d','t'), ('l'), ('m','n'), ('r')  ]

def soundex(name):
    name = name.lower().split(' ')
    
    first_l = [ e[0].upper() for e in name ] 
    
    let_to_dig = loop( lambda x: indx(x, tr), loop( lambda x: x, name, lambda x: x not in 'hw' ) )
    
    del_duble = loop( lambda x: x[0], let_to_dig, funk2 = lambda x:groupby(x) )
    
    del_vowel = [[e[0],''.join([ x for i,x in enumerate(e) if x.isdigit() and i  ])] for e in del_duble ]
    
    return ' '.join((([first_l[i] ,e[0].upper()][all((e[0].isalpha(), e[0] == first_l[i]))] + ['',e[0]][all((e[0].isdigit(), first_l[i] in 'HW'))]) + e[1]).ljust(4,"0")[:4] 
              for i,e in enumerate(del_vowel) )
    
def indx(elem, arr):
    for i, x in enumerate(arr):
        if elem in x:
            return str(i)
    return elem
            
def loop(func1, arr, excuse1=lambda x:x , excuse2=lambda x:x, funk2=lambda x:x):
    return [ [func1(x) for x in funk2(e) if excuse1(x)] for e in arr if excuse2(e) ]


import re
def soundex(s):
    d, li = {k:i for i,j in zip(list(range(1, 7)), ['bfpv','cgjkqsxz','dt','l','mn','r'])for k in j}, []
    for i in s.split():
        first = i[0]
        i = first+re.sub(r'[hwHW]','',i[1:])
        i = re.sub(r'[^aeiouy]', lambda x: str(d.get(x.group().lower(), x.group())), i)
        i = re.sub(r'(\d)(\1+)', r'\1', i)
        i = i[0] + re.sub(r'[aeiouyAEIOUY]', '', i[1:])
        li.append(first.upper() + (f"{i[1:]:<03}")[:3])
    return " ".join(li)

def soundex(name):
    consonants_to_digits = {c: str(i)
        for i, consonants in enumerate("bfpv cgjkqsxz dt l mn r".split(), 1)
        for cs in consonants
        for c in cs}
    def soundex_word(word):
        result = word.lower()
        result = (c for i, c in enumerate(result) if i == 0 or c not in "hw")
        result = (consonants_to_digits.get(c, c) for c in result)
        result = uniq(result)
        result = (c for i, c in enumerate(result) if i == 0 or c not in "aeiouy")
        result = "".join(result)
        result = word[0].upper() + result[1:]
        result = format(result, "0<4.4")
        return result
    return " ".join(soundex_word(word) for word in name.split())

def uniq(iterable):
    iterable = iter(iterable)
    previous = next(iterable)
    yield previous
    for elem in iterable:
        if elem != previous:
            yield elem
            previous = elem

CONS_VAL = {
    'b': '1', 'f': '1', 'p': '1', 'v': '1', 'c': '2', 'g': '2',
    'j': '2', 'k': '2', 'q': '2', 's': '2', 'x': '2', 'z': '2',
    'd': '3', 't': '3', 'l': '4', 'm': '5', 'n': '5', 'r': '6' }

def soundex(name):
    result = []
    
    for word in name.lower().split():
        # save the initial
        first = word[0]
        
        # remove h, w
        word = [first] + [ c for c in word[1:] if c not in 'hw' ]
        
        # replace consonants
        word = [ CONS_VAL.get(c, c) for c in word ]
        
        # remove duplicates
        word = [first] + [ c for i, c in enumerate(word[1:]) if word[i] != c ]
        
        # remove vowels
        word = [first] + [ c for c in word[1:] if c not in 'aeiouy' ]
        
        # append zeros and cut
        word = (word + ['0'] * 3)[:4]
        result.append( ''.join(word) )
    
    return ' '.join(result).upper()

from itertools import groupby,islice

tr=str.maketrans('ABCDEFGIJKLMNOPQRSTUVXYZ','012301202245501262301202','HW')

def soundex(n):
    n=n.upper()
    ws=[]
    for w in n.split(' '):
        s=[]
        s=list(islice((vg[0] for i,vg in enumerate(groupby(w.translate(tr))) if vg[0]!='0' or i==0),4))
        if s[0]=='0' or s[0]==w[0].translate(tr):
            s[0]=w[0]
        else:
            s.insert(0,w[0])
        ws.append(''.join(s)[:4].ljust(4,'0'))
    return ' '.join(ws)


import re
def soundex(s):
    d, li = {k:i for i,j in zip(list(range(1, 7)), ['bfpv','cgjkqsxz','dt','l','mn','r'])for k in j}, []
    for i in s.split():
        first = i[0].upper()
        i = re.sub(r'(\d)(\1+)',r'\1',re.sub(r'[^aeiouy]',lambda x:str(d.get(x.group().lower(),x.group())),first+re.sub(r'[hwHW]','',i[1:])))
        i = i[0] + re.sub(r'[aeiouyAEIOUY]', '', i[1:])
        li.append(first + (f"{i[1:]:<03}")[:3])
    return " ".join(li)

import re

def soundex(name):
    sounds = []
    namelist = name.split()
    
    
    
    for namey in namelist:
        firstletter = namey[0].upper()
        temp = namey.lower()
        temp = re.sub('[hw]', "", temp)
        temp = re.sub('[aeiouy]', "*", temp)
        temp = re.sub('[bfpv]', "1", temp)
        temp = re.sub('[cgjkqsxz]', "2", temp)
        temp = re.sub('[dt]', "3", temp)
        temp = re.sub('[l]', "4", temp)
        temp = re.sub('[mn]', "5", temp)
        temp = re.sub('[r]', "6", temp)
        temp = re.sub(r'(.)\1+', r'\1', temp) 
        
        if firstletter in ["H", "W"]:
            tempcode = firstletter + temp + "0000"
        else:
            tempcode = firstletter + temp[1:] + "0000"
        tempcode = re.sub("[*]", "", tempcode)
        
        sounds.append(tempcode[0:4])
        
   
        
    
    return " ".join(sounds)