所以我有一组相当简单的数据,例如:
['test.sh','api.test.sh','blah.api.test.sh','test.com','api.test.com']
我需要转换为分层数据结构,我想用字典做这个:
{ 'name':'test.sh',
'children': { 'name':'api.test.sh',
'children': { 'name':'blah.api.test.sh' }
}
},
{
'name':'test.com',
'children': { 'name':'api.test.com' }
}
基本上对于每个高级别的名字,我都可以按照自己的方式工作并执行我需要做的操作。
我的问题更多地与创建一种简单的方法来排序,匹配和转换数据有关。我可以想到几种方法来做到这一点,但我无法想到任何相当优雅的东西。我也是在python中这样做的。
由于
答案 0 :(得分:1)
我认为这可能就是你要找的东西:
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答案,这也很有效,他的解决方案肯定是最诡异的。这个的优点是它不需要任何进口。但你真的应该认为roippi的答案是最优雅的。答案 1 :(得分:1)
所以,我认为通过三个步骤正确解决了这个问题:排序,组,格式。
首先,排序输入您的输入以将它们排列在逻辑组中。您可以定义快速辅助函数来定义排序键:
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
blah.com
x.y.z.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"
}
]
最后,您需要格式化这些组到您想要的层次结构中。这是一个快速而肮脏的实现:
sub1.example.com
最后一个实现取决于几个假设,即在给定组中不会有任何等效长度的netlocs,即sub2.example.com
和{{1}}永远不会发生。显然你可以根据需要调整实现。