排序和组织的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的答案。
于是,我看到了这个问题的三个步骤发生适当的解决办法:排序,组,格式。
首先,排序将您的输入排列在逻辑组中。您可以定义一个快速的辅助函数来定义排序关键字:
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.com
的blah.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.com
和sub2.example.com
永远不会发生。显然你可以根据需要调整实现。
谢谢!看到其他人的实现很棒,很好的答案! – sbrichards 2014-10-31 23:56:09
谢谢!这看起来不错,我实际上想出了一个类似的方法,所以很高兴看到我并不孤单。 – sbrichards 2014-10-31 23:56:50