好的,这是我的头脑。我有两个带有对象组的字典,如下所示:
groups = {
'servers': ['unix_servers', 'windows_servers'],
'unix_servers': ['server_a', 'server_b', 'server_group'],
'windows_servers': ['server_c', 'server_d'],
'server_group': ['server_e', 'server_f']
}
hosts = {
'server_a': '10.0.0.1',
'server_b': '10.0.0.2',
'server_c': '10.0.0.3',
'server_d': '10.0.0.4',
'server_e': '10.0.0.5',
'server_f': '10.0.0.6'
}
我正在寻找的输出是:
d3 = {
'servers': {
'unix_servers': {
'server_a': '10.0.0.1',
'server_b': '10.0.0.2',
'server_group': {
'server_e': '10.0.0.5',
'server_f': '10.0.0.6'
}
},
'windows_servers': {
'server_c': '10.0.0.3',
'server_d': '10.0.0.4'
}
}
}
我遇到的问题是我事先不知道有多少递归级别,因为嵌套组在理论上可以无限进行。另外,我在确定哪些键应该是组合字典中的顶级键时遇到了麻烦。
我目前有以下内容:
def resolve(d1, d2):
for k, v in d1.items():
for i in v:
if i in d2.keys():
d3[k] = {i: d2[i]}
这将返回:
{
"servers": {
"unix_servers": {
"server_a": "10.0.0.1",
"server_b": "10.0.0.2",
"server_group": {
"server_e": "10.0.0.5",
"server_f": "10.0.0.6"
}
},
"windows_servers": {
"server_c": "10.0.0.3",
"server_d": "10.0.0.4"
}
},
"unix_servers": {
"server_b": "10.0.0.2"
},
"windows_servers": {
"server_d": "10.0.0.4"
},
"server_group": {
"server_f": "10.0.0.6"
}
}
这很接近,但是显然缺少递归并且不处理键的嵌套。主要是在这里寻找指针,递归逻辑还不适合我...
答案 0 :(得分:3)
我认为这可以满足您的要求
def resolve(groups, hosts):
# Groups that have already been resolved
resolved_groups = {}
# Group names that are not root
non_root = set()
# Make dict with resolution of each group
result = {}
for name in groups:
result[name] = _resolve_rec(name, groups, hosts, resolved_groups, non_root)
# Remove groups that are not root
for name in groups:
if name in non_root:
del result[name]
return result
def _resolve_rec(name, groups, hosts, resolved_groups, non_root):
# If group has already been resolved finish
if name in resolved_groups:
return resolved_groups[name]
# If it is a host finish
if name in hosts:
return hosts[name]
# New group resolution
resolved = {}
for child in groups[name]:
# Resolve each child
resolved[child] = _resolve_rec(child, groups, hosts, resolved_groups, non_root)
# Mark child as non-root
non_root.add(child)
# Save to resolved groups
resolved_groups[name] = resolved
return resolved
以您的示例为例:
groups = {
'servers': ['unix_servers', 'windows_servers'],
'unix_servers': ['server_a', 'server_b', 'server_group'],
'windows_servers': ['server_c', 'server_d'],
'server_group': ['server_e', 'server_f']
}
hosts = {
'server_a': '10.0.0.1',
'server_b': '10.0.0.2',
'server_c': '10.0.0.3',
'server_d': '10.0.0.4',
'server_e': '10.0.0.5',
'server_f': '10.0.0.6'
}
d3 = {
'servers': {
'unix_servers': {
'server_a': '10.0.0.1',
'server_b': '10.0.0.2',
'server_group': {
'server_e': '10.0.0.5',
'server_f': '10.0.0.6'
}
},
'windows_servers': {
'server_c': '10.0.0.3',
'server_d': '10.0.0.4'
}
}
}
print(resolve(groups, hosts) == d3)
# True
请注意,如果您的组A
包含组B
,但组B
包含组A
,则对于格式错误的输入,这可能会无限递归。 >
答案 1 :(得分:1)
假设您可以使用交叉引用数据结构,则不必在此处使用递归。
from itertools import chain
group_dicts = {k: {} for k in groups}
for g in group_dicts:
for child_key in groups[g]:
child = group_dicts.get(child_key, hosts.get(child_key))
group_dicts[g][child_key] = child
# remove entries that are referenced at least once
not_top_levels = set(chain.from_iterable(groups.values()))
result = {g: group_dicts[g] for g in group_dicts if g not in not_top_levels}
与其他解决方案不同,这将正确处理循环和无限递归的组,因为所有dict引用都是共享的。当您的groups
拓扑描述一棵树时,这将与递归解决方案完全相同。但是,如果您的groups
在拓扑上描述了有向无环图,则此解决方案将共享出现多次的所有节点的字典,而递归解决方案会将副本复制并扩展到规则树中,这将不会如果您不需要更改命令,那真的不是问题。如果您的groups
在拓扑上描述了带有循环的图,则将创建这些循环,而递归解将由于无限递归而下降。
答案 2 :(得分:1)
您可以使用简单的递归:
def build(val):
return {i:build(i) for i in groups[val]} if val in groups else hosts[val]
import json
print(json.dumps({'servers':build('servers')}, indent=4))
输出:
{
"servers": {
"unix_servers": {
"server_a": "10.0.0.1",
"server_b": "10.0.0.2",
"server_group": {
"server_e": "10.0.0.5",
"server_f": "10.0.0.6"
}
},
"windows_servers": {
"server_c": "10.0.0.3",
"server_d": "10.0.0.4"
}
}
}
答案 3 :(得分:0)
<div class="container">
<div class="block">
</div>
</div>
这将给出:
d3={}
main={}
for i in groups['servers']:
if(i in groups):
d={}
for j in groups[i]:
if(j in groups):
dd={}
for k in groups[j]:
dd[k]=hosts[k]
d[j]=dd
else:
d[j]=hosts[j]
main[i]=d
d3['servers']=main
print(d3)
答案 4 :(得分:0)
我想它只需要两个循环,就不再需要。在这里,dict
组将被更新,更确切地说,它将丢失一些键值。
groups = {k: {s: None for s in subs} for k, subs in groups.items()}
for k, subs in groups.items():
for subs_k, subs_v in subs.items():
if subs_v is not None:
continue
if subs_k in groups:
groups[k][subs_k] = groups[subs_k]
del groups[subs_k]
else:
groups[k][subs_k] = hosts[subs_k]
print(groups)
您可能想使用defaultdict
对其进行重写答案 5 :(得分:0)
这是python的新手,但我一直在为此苦苦挣扎,但终于找到了解决方案,尽管时间很长。
groups = {
'servers': ['unix_servers', 'windows_servers'],
'unix_servers': ['server_a', 'server_b', 'server_group'],
'windows_servers': ['server_c', 'server_d'],
'server_group': ['server_e', 'server_f']
}
hosts = {
'server_a': '10.0.0.1',
'server_b': '10.0.0.2',
'server_c': '10.0.0.3',
'server_d': '10.0.0.4',
'server_e': '10.0.0.5',
'server_f': '10.0.0.6'
}
result = {}
parent = '';
levels = [];
def check(s,r):
if(r[s]==''): #check for each blank element in the result recursively
sublist = {}
for k in groups[s]: # check if the key exist in group if exist append children to result.
if k in hosts :
sublist[k] = hosts[k] # check if host exist in hosts for this key
else:
sublist[k]=''
if(key_exist(result, s)): # check if the key exist in result if exist append to result.
d = result
p = None
for key in levels:
p = d
d = d[key]
p[key] = sublist
del levels[:]
for x in sublist :
if(sublist[x] == ''):
check(x,p[key])
def resolve(r):
for s in r:
if(isinstance(r[s],dict)):
return resolve(r[s])
else:
check(s,r)
def key_exist(groups, key):
for s in groups:
if key in groups:
levels.append(key);
return True
else:
if(isinstance(groups[s],dict)):
levels.append(s);
return key_exist(groups[s], key)
return False
# Find the root or parent element
for k in groups.keys():
found = False
for j in groups.keys():
if k in groups[j]:
found = False
else:
found = True
if(found):
parent = k # root or parent element
# start making result with root element
s = {}
for k in groups[parent]:
s[k]='' # initialize child elements with blank
result[parent] = s
resolve(result)
print(result)