我有这样一本字典:
d = {
'hosts': [
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra_check_cmd': 'check-me'},
{'hostname': 'def', 'ip': '127.0.0.2', 'extra_check_cmd': 'check-it,check-this'},
{'hostname': 'ijk,uvw,xyz', 'ip': '127.0.0.3,127.0.0.4,127.0.0.5', 'extra': 'check-me,check-this,check-it'}
]
}
我想从中创建以下字典
d = {
'hosts': [
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra_check_cmd': 'check-me'},
{'hostname': 'def', 'ip': '127.0.0.2', 'extra_check_cmd': 'check-it'},
{'hostname': 'def', 'ip': '127.0.0.2', 'extra_check_cmd': 'check-this'},
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-me'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-me'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-me'}
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-it'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-it'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-it'}
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-this'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-this'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-this'}
]
}
这意味着在给定值列表的任何地方,每个值列表都应该有一个单独的子字典。
最佳答案
也许是这样的?
def expand_dict(host):
# Create all of the possible key-value pairs for each key in the original dictionary
kv_pairs = [[(k, v) for v in vals.split(",")] for k, vals in host.items()]
# Find the number of dictionaries this would expand to
max_len = max(len(p) for p in kv_pairs)
# A list of possible values must either be the length of the number of dictionaries we expect, or length 1 so we can repeat the value max_len times
assert all(len(pairs) in {1, max_len} for pairs in kv_pairs)
# Expand all of the length 1 value lists to length max_len
updated_pairs = [p if len(p) == max_len else p * max_len for p in kv_pairs]
# Return a generator of dictionaries for each of the sets of key-value pairs
return (dict(pairs) for pairs in zip(*updated_pairs))
input_dict = {'hosts': [{'hostname': 'abc', 'ip': '127.0.0.1', 'extra_check_cmd': 'check-me'}, {'hostname': 'def', 'ip': '127.0.0.2', 'extra_check_cmd': 'check-it,check-this'}, {'hostname': 'ijk,uvw,xyz', 'ip': '127.0.0.3,127.0.0.4,127.0.0.5', 'extra': 'check-me'}]}
output_dict = {'hosts': [d for host in input_dict['hosts'] for d in expand_dict(host)]}
进一步分解,让我们尝试一个例子。在本例中,我使用的是 host = d['hosts'][2]
。
{'hostname': 'ijk,uvw,xyz',
'ip': '127.0.0.3,127.0.0.4,127.0.0.5',
'extra': 'check-me'}
行 kv_pairs = [[(k, v) for v in vals.split(",")] for k, vals in host.items()]
给了我们可能的键列表- 内部项目列表的值对。
[
[('hostname', 'ijk'), ('hostname', 'uvw'), ('hostname', 'xyz')],
[('ip', '127.0.0.3'), ('ip', '127.0.0.4'), ('ip', '127.0.0.5')],
[('extra', 'check-me')],
]
如您所见,"hostname"
和 "ip"
键各有 3 个键值对, 只有 1 对原始主机字典中的“extra”
键。目标是生成 3 个字典,每个字典中都有 'extra': 'check-me'
。因此,我们想要找到我们期望生成的词典数量。
行 max_len = max(len(p) for p in kv_pairs)
给我们 3。然后,就像完整性检查一样,我们要确保每组键值对in kv_pairs
要么是长度 1,要么是长度 3。如果是其他任何东西,问题就不好定义,所以我们添加断言 assert all(len(pairs) in {1, max_len} 对于 kv_pairs 中的对)
。
然后我们通过重复将所有长度为 1 的 kv 对列表扩展为长度 3。这个列表理解基本上采用所有长度为 3 的列表,并重复长度为 1 的列表,每个列表 3 次,因此它们的长度都相同。
updated_pairs = [p if len(p) == max_len else p * max_len for p in kv_pairs]
[[('hostname', 'ijk'), ('hostname', 'uvw'), ('hostname', 'xyz')],
[('ip', '127.0.0.3'), ('ip', '127.0.0.4'), ('ip', '127.0.0.5')],
[('extra', 'check-me'), ('extra', 'check-me'), ('extra', 'check-me')]]
既然一切都准备好了,我们就可以开始创建字典了。我们可以为此使用 zip()
,它为我们提供元组迭代器,其中包含我们传入的每个输入迭代器中的项目。我正在使用 Python 的解包语法来扩展 updated_kv_pairs 中的每个列表
作为 zip()
的单独参数。换句话说,
zip(*updated_kv_pairs)
与
相同zip(updated_kv_pairs[0], updated_kv_pairs[1], updated_kv_pairs[2])
zip()
的每次迭代都为我们提供了我们输出的单个字典中的键值对列表。这给了我们
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-me'}
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-me'}
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-me'}
关于python-3.x - 使用其中的值列表创建单独的字典,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70419187/