Implement a function which 
creates a **[radix tree](https://en.wikipedia.org/wiki/Radix_tree)** (a space-optimized trie [prefix tree]) 
in which each node that is the only child is merged with its parent [unless a word from the input ends there]) 
from a given list of words 
using dictionaries (aka hash maps or hash tables) where:

1. The dictionary keys are the nodes.
2. Leaf nodes are empty dictionaries.
3. The value for empty input is an empty dictionary.
4. Words are all lowercase or empty strings.
5. Words can contain duplicates.

### Examples:

```python
>>> radix_tree()
{}

>>> radix_tree("")
{}

>>> radix_tree("", "")
{}

>>> radix_tree("radix", "tree")
{"radix": {}, "tree": {}}

>>> radix_tree("ape", "apple")
{"ap": {"e": {}, "ple": {}}}

>>> radix_tree("apple", "applet", "apple", "ape")
{"ap": {"ple": {"t": {}}, "e": {}}}

>>> radix_tree("romane", "romanus", "romulus", "rubens", "rubicon", "rubicundus")
{"r": {"om": {"an": {"e": {}, "us": {}}, "ulus": {}},
       "ub": {"ens": {}, "ic": {"on": {}, "undus": {}}}}}

>>> radix_tree("appleabcd", "apple")
{"apple": {"abcd": {}}}
```

Difficulty: introductory

Starter code:

def radix_tree(*words):
	

Solutions:
from itertools import groupby
from operator import itemgetter
from os.path import commonprefix

first = itemgetter(0)

def radix_tree(*words):
    words = [w for w in words if w]
    result = {}
    for key, grp in groupby(sorted(words), key=first):
        lst = list(grp)
        prefix = commonprefix(lst)
        result[prefix] = radix_tree(*(w[len(prefix):] for w in lst))
    return result

def radix_tree(*words):
    byFirstChar={}
    for w in words:
        if w != "":
            l=byFirstChar.get(w[0],[])
            l.append(w[1:])
            byFirstChar[w[0]]=l
    result={}
    for c,l in byFirstChar.items():
        rt=radix_tree(*l)
        if len(rt) == 1 and not '' in l:
            for key,value in rt.items():
                c=c+key
                rt=value
        result[c]=rt
    return result

from itertools import groupby
def radix_tree(*d, need=1):
    if not {i for i in d if i} : return {} 
    store = {}
    for i, j in groupby(sorted(d) if need else d, lambda x: x[0]):
        words = list(j)
        if len(words) == 1 : store[words[0]] = {}
        else:
            common = next((j for j, i in enumerate(zip(*words)) if len(set(i)) != 1), len(min(words, key=len)))
            store[words[0][:common]] = radix_tree(*[i[common:] for i in words if i[common:]],need = 0)
    return store

from os.path import commonprefix

def radix_tree(*words):
    groups = {}
    for word in words:
        if word:
            groups[word[0]] = groups.get(word[0], []) + [word]
    root = {}
    for group in groups.values():
        prefix = commonprefix(group)
        root[prefix] = radix_tree(*(w[len(prefix):] for w in group))
    return root

def radix_tree(*W):
    D={}
    for w in W:
        if w:D[w[0]]=D.get(w[0],[])+[w[1:]]
    Z={}
    for k in D:
        T=radix_tree(*D[k])
        if len(T)==1and''not in D[k]:
            for j in T:k,T=k+j,T[j]
        Z[k]=T
    return Z

def radix_tree(*a):
    r = {}
    for s in a:
        d = r
        for x in s + "*":
            if x not in d: d[x] = {}
            d = d[x]
    def g(d):
        dd = {}
        for x in d:
            d[x] = g(d[x])
            if len(d[x]) == 1:
                k, v = [*d[x].items()][0]
                dd[x+k] = v
            else:
                dd[x] = d[x]
        return dd
    def h(d):
        dd = {}
        for x in d:
            d[x] = h(d[x])
            if x != "*":
                dd[x if x[-1] != "*" else x[:-1]] = d[x]
        return dd
    return h(g(r))

def radix_tree(*Q) :
    U,R = set(Q),{}
    for Q in Q :
        T = R
        for Q in Q :
            if not Q in T : T[Q] = {}
            T = T[Q]
    def H(Q,S) :
        T = list(Q)
        for V in T :
            if 1 == len(Q[V]) and (S + V) not in U :
                B = next(iter(Q[V]))
                Q[V + B] = Q[V][B]
                del Q[V]
                T.append(V + B)
            else : H(Q[V],S + V)
    H(R,'')
    return R

from itertools import groupby

def radix_tree(*words):
    d = {}
    if not any(words): return d
    words = sorted(words)
    for g in (list(g) for _,g in groupby(words, key=lambda w:w[0] if w else '')):
        i = next((i for i in range(len(g[0])) if not all(len(w) > i and w[i] == g[0][i] for w in g)), len(g[0]))
        d[g[0][:i]] = radix_tree(*(w[i:] for w in g if len(w) > i))
    return d
        
        


from itertools import groupby
def radix_tree(*d):
    if not {i for i in d if i} : return {} 
    store = {}
    for i, j in groupby(sorted(d), lambda x: x[0]):
        words = list(j)
        if len(words) == 1 : store[words[0]] = {}
        else:
            common = next((j for j, i in enumerate(zip(*words)) if len(set(i)) != 1), len(min(words, key=len)))
            store[words[0][:common]] = radix_tree(*[i[common:] for i in words if i[common:]])
    return store

from functools import reduce

def splitAlong(xs, ys):
    i = 0
    try:
        while xs[i] == ys[i]:
            i += 1
    except IndexError:
        pass
    return (xs[:i], xs[i:], ys[i:])

def insert(tree, word):
    for key, val in tree.items():
        pref, wt, kt = splitAlong(word, key)
        if pref:
            if kt:
                del tree[key]
                tree[pref] = {wt: {}, kt: val} if wt else {kt: val}
            else:
                insert(tree[pref], wt)
            return tree
    if word:
        tree[word] = {}
    return tree


def radix_tree(*words):
    return reduce(insert, words, {})