Remove Common Host Name Elements (Reduce Host Names) - DRY

Explanation:

I wrote the following function to shorten the hostnames of machines used in production. Here the names have been changed, but the same structure and format have been preserved. The code below is inconvenient, and I would like to make DRY (Do not Repeat Yourself) code . Readability is also important, as it is code that you may need to save or understand not only by yourself.

Code:

def shorten_hostnames(machines):
    # split items
    d = {k: v.split('.') for k, v in machines.items()}
    # trim end
    while all(d.values()):
        if not len(set([v[-1] for v in d.values()])) == 1:
            break
        if not all(len(v) > 1 for v in d.values()):
            break
        d = {k: v[:-1] for k, v in d.items()}
    # trim start
    while all(d.values()):
        if not len(set([v[0] for v in d.values()])) == 1:
            break
        if not all(len(v) > 1 for v in d.values()):
            break            
        d = {k: v[1:] for k, v in d.items()}
    # join items
    d = {k: '.'.join(v) for k, v in d.items()}
    # return shortened hostnames
    return d

Input Example:

machines = {'a.ace.site.info': 'a.ace.site.info',
            'b.ace.site.info': 'b.ace.site.info',
            'a.bob.site.info': 'a.bob.site.info',
            'b.bob.site.info': 'b.bob.site.info',} 

Output:

>>> for k, v in shorten_hostnames(machines).items():
    print k, '-->', v

b.ace.site.info --> b.ace
a.ace.site.info --> a.ace
b.bob.site.info --> b.bob
a.bob.site.info --> a.bob

Where and why do I need your help:

, , , , . , , , , - .

:

, "Gotcha". ( machines = {'a.ace.site.info': 'a.ace.site.info'}), ( a). - . - ( )

:

, , , . , ( ), , , , , .

:

# In
machines = {'ace.a.site.info': 'ace.a.site.info',
            'ace.b.site.info': 'ace.b.site.info',}
# Out
ace.b.site.info --> b
ace.a.site.info --> a

# In
machines = {'a.ace.site.info': 'a.ace.site.info',}
# Out
a.ace.site.info --> a

# In
machines = {'ace.a.site.info': 'ace.a.site.info',
            'ace.b.site.com': 'ace.b.site.com',}
# Out
ace.b.site.com --> b.site.com
ace.a.site.info --> a.site.info
+4
2

, , :

def shorten_hostnames(machines):
    keys, values = zip(*machines.items())
    values = [v.split('.') for v in values]
    for i, s in ((-1, slice(-1)), (0, slice(1, None))):
        while all(values):
            if not len(set(v[i] for v in values)) == 1:
                break
            if any(len(v) <= 1 for v in values):
                break
            values = [v[s] for v in values]
    return {k: '.'.join(v) for k, v in zip(keys, values)}

, , :

from itertools import dropwhile, izip_longest

def remove_common_prefix(*parts):
    # always leaves a last common element in place
    zipped = izip_longest(*(p[:-1] for p in parts), fillvalue=None)
    stripped = dropwhile(lambda v: len(set(v)) == 1, zipped)
    res = [filter(None, part) + (old[-1],) for part, old in zip(zip(*stripped), parts)]
    # filtered everything away? Then return just the last parts
    return res or [p[-1:] for p in parts]

def shorten_hostnames(machines):
    # edge-case; faster to just return the first part
    if len(machines) == 1:
        return {k: v.split('.', 1)[0] for k, v in machines.items()}
    keys, values = zip(*machines.items())  # for easier processing and re-assembling
    parts = remove_common_prefix(*(v.split('.')[::-1] for v in values))
    parts = remove_common_prefix(*(part[::-1] for part in parts))
    return {k: '.'.join(v) for k, v in zip(keys, parts)}

, :

>>> shorten_hostnames(machines)
{'b.ace.site.info': 'b.ace', 'a.ace.site.info': 'a.ace', 'b.bob.site.info': 'b.bob', 'a.bob.site.info': 'a.bob'}
>>> shorten_hostnames({'foo': 'a.ace.site', 'bar': 'a.ace.site.info'})
{'foo': 'site', 'bar': 'site.info'}
>>> shorten_hostnames({'ace.a.site.info': 'ace.a.site.info', 'ace.b.site.info': 'ace.b.site.info'})
{'ace.b.site.info': 'b', 'ace.a.site.info': 'a'}
>>> shorten_hostnames({'ace.a.site.info': 'ace.a.site.info'})
{'ace.a.site.info': 'ace'}
+4
def shorten_hostnames(machines):
    def trim(hostnames, head=True):
        while all(len(v) > 1 for v in hostnames) and len(set(v[0 if head else -1] for v in hostnames)) == 1:
            hostnames[:] = [v[1:] if head else v[:-1] for v in hostnames]

    keys, values = zip(*machines.items())
    hostnames = [v.split('.') for v in values]
    trim(hostnames, False)
    trim(hostnames)
    return {k: '.'.join(v) for k, v in zip(keys, hostnames)}
+2

All Articles