排序和组织的DNS记录

问题描述:

所以我有一个非常简单的数据集,如: ['test.sh','api.test.sh','blah.api.test.sh','test.com','api.test.com']排序和组织的DNS记录

,我需要转变成一个分层数据结构,我想用字典这样做的:

{ 'name':'test.sh', 
    'children': { 'name':'api.test.sh', 
       'children': { 'name':'blah.api.test.sh' } 
       } 
}, 
{ 
    'name':'test.com', 
    'children': { 'name':'api.test.com' } 
} 

基本上,对于每个高级别的名称,我可以按照自己的方式工作,并执行我需要执行的操作。

我的问题与创建一个简单的排序,匹配和转换数据的方法有关。我可以想出几种方法来做到这一点,但我想不出任何相当优雅的东西。另外我在Python中这样做。

感谢

我认为这可能是你在找什么:

def sort_dns(l): 


    to_return = [] 
    # Get top-level domains: the domains that contain the less amount of dots. 
    count_list = [i.count('.') for i in l] 
    min_dots = min(count_list) 
    top_domains = [i for i in l if i.count('.') == min_dots] 
    # Now for each domain, we find it subdomains. 
    for domain in top_domains: 
     sub_domains = [i for i in l if domain in i and i is not domain] 
     #And untill we aren't at the deepest level, we continue looking for sub domains and repeat the structure 
     sub_sub_domains = sort_dns(sub_domains) if not len(sub_domains) == 0 else None 
     to_return.append({'name' : domain, 'childrens' : sub_sub_domains}) 

    return to_return 

正如你看到这个函数调用自身递归如果需要去无限“深”。

你的榜样,结果是以下

[ 
    { 
     'name': 'test.sh', 
     'childrens': [ 
      { 
       'name': 'api.test.sh', 
       'childrens': [ 
        {'name': 'blah.api.test.sh', 'childrens': None} 
       ] 
      } 
     ] 
    }, 
    { 
     'name': 'test.com', 
     'childrens': [ 
      {'name': 'api.test.com', 'childrens': None} 
     ] 
    } 
] 

正如你看到它处理多个儿童的情况下,并没有孩子的。

需要注意的是,如果你不希望'childrens': None做,您可以将功能更改为:

def sort_dns(l): 


    to_return = [] 
    # Get top-level domains: the domains that contain the less amount of dots. 
    count_list = [i.count('.') for i in l] 
    min_dots = min(count_list) 
    top_domains = [i for i in l if i.count('.') == min_dots] 
    # Now for each domain, we find it subdomains. 
    for domain in top_domains: 
     sub_domains = [i for i in l if domain in i and i is not domain] 
     #And untill we aren't at the deepest level, we continue looking for sub domains and repeat the structure 
     sub_sub_domains = sort_dns(sub_domains) if not len(sub_domains) == 0 else None 
     if sub_sub_domains: 
      to_return.append({'name' : domain, 'childrens' : sub_sub_domains}) 
     else: 
      to_return.append({'name' : domain}) 

    return to_return 

注意,这是Python3代码。

编辑:我读过roippi答案和这个伟大的作品,他的解决方案肯定是最pythonic。这个优点是它不需要任何进口。但是你应该认真考虑roippi的答案。

+0

谢谢!这看起来不错,我实际上想出了一个类似的方法,所以很高兴看到我并不孤单。 – sbrichards 2014-10-31 23:56:50

于是,我看到了这个问题的三个步骤发生适当的解决办法:排序格式

首先,排序将您的输入排列在逻辑组中。您可以定义一个快速的辅助函数来定义排序关键字:

def sorter(netloc): 
    split = netloc.split('.') 
    return (split[::-1], -len(split)) 

正是如此使用它:

data = ['test.sh','api.test.sh','blah.api.test.sh','test.com','api.test.com', 'another.com', 'sub.another.com', 'sub.sub.another.com'] 

#shuffling data, to show that sorting works 
import random 
random.shuffle(data) 

sorted(data, key=sorter) 
Out[14]: 
['another.com', 
'sub.another.com', 
'sub.sub.another.com', 
'test.com', 
'api.test.com', 
'test.sh', 
'api.test.sh', 
'blah.api.test.sh'] 

现在,一切都在正确的顺序,做一个类似荷兰国际集团运作与itertools.groupby这组由x.y.z.blah.comblah.com部分:

def grouper(netloc): 
    return ''.join(netloc.split('.')[-2:]) 

#in-place sort, replicating sorted() call above 
data.sort(key=sorter) 

from itertools import groupby 

[list(g) for k,g in groupby(data, grouper)] 
Out[27]: 
[['another.com', 'sub.another.com', 'sub.sub.another.com'], 
['test.com', 'api.test.com'], 
['test.sh', 'api.test.sh', 'blah.api.test.sh']] 

末你需要格式这些组合到你想要的层次。这里是一个快速和肮脏的实现:

def make_hierarchy(groups): 
    from copy import deepcopy 
    _groups = deepcopy(groups) 
    ret = [] 
    for li in _groups: 
     current = {} 
     ret.append(current) 
     while li: 
      current['name'] = li.pop() 
      if li: 
       nxt = {} 
       current['children'] = nxt 
       current = nxt 
    return ret 

print(json.dumps(make_hierarchy(grouped), indent=2)) 
[ 
    { 
    "children": { 
     "children": { 
     "name": "another.com" 
     }, 
     "name": "sub.another.com" 
    }, 
    "name": "sub.sub.another.com" 
    }, 
    { 
    "children": { 
     "name": "test.com" 
    }, 
    "name": "api.test.com" 
    }, 
    { 
    "children": { 
     "children": { 
     "name": "test.sh" 
     }, 
     "name": "api.test.sh" 
    }, 
    "name": "blah.api.test.sh" 
    } 
] 

这最后的实施取决于几个假设,即不会有同组中的任何等效长度netlocs,即sub1.example.comsub2.example.com永远不会发生。显然你可以根据需要调整实现。

+0

谢谢!看到其他人的实现很棒,很好的答案! – sbrichards 2014-10-31 23:56:09