我有一个字典
foo:
a:
aa1: 1
aa2: 2
b:
bb1: 3
bb2: 4
我想将其转换为:
- {key:a, subkey:aa1, value: 1}
- {key:a, subkey:aa2, value: 2}
- {key:b, subkey:bb1, value: 3}
- {key:b, subkey:bb2, value: 4}
如果只能用 json_query 实现,我会接受。但最好不要使用复杂的 JMESPath 公式。
更新
foo_arr: "{{ foo|ansible.utils.to_paths|dict2items }}"
foo_key: "{{ foo_arr|map(attribute='key')|map('split', '.') }}"
foo_val: "{{ foo_arr|map(attribute='value') }}"
bar: "{{ foo_key|zip(foo_val)|map('flatten')
|map('zip', ['key', 'subkey', 'value'])
|map('map', 'reverse')
|map('community.general.dict') }}"
给你想要的东西
bar:
- {key: a, subkey: aa1, value: 1}
- {key: a, subkey: aa2, value: 2}
- {key: b, subkey: bb1, value: 3}
- {key: b, subkey: bb2, value: 4}
注意:此解决方案仅限于不带点的按键。
用于测试的完整剧本示例
- hosts: all
vars:
foo:
a:
aa1: 1
aa2: 2
b:
bb1: 3
bb2: 4
foo_arr: "{{ foo|ansible.utils.to_paths|dict2items }}"
foo_key: "{{ foo_arr|map(attribute='key')|map('split', '.') }}"
foo_val: "{{ foo_arr|map(attribute='value') }}"
bar: "{{ foo_key|zip(foo_val)|map('flatten')
|map('zip', ['key', 'subkey', 'value'])
|map('map', 'reverse')
|map('community.general.dict') }}"
tasks:
- debug:
var: bar|to_yaml
起源
例如,
- set_fact:
bar: "{{ bar|d([]) + [{'key': _key,
'subkey': _sub,
'value': _val|int}] }}"
loop: "{{ foo|ansible.utils.to_paths|dict2items }}"
vars:
_arr: "{{ item.key.split('.') }}"
_key: "{{ _arr.0 }}"
_sub: "{{ _arr.1 }}"
_val: "{{ item.value }}"
给予
bar:
- {key: a, subkey: aa1, value: 1}
- {key: a, subkey: aa2, value: 2}
- {key: b, subkey: bb1, value: 3}
- {key: b, subkey: bb2, value: 4}
问:“密钥可能是IP地址,因此它损坏了。”
A:您可以通过索引轻松解决这个问题,例如
vars:
_arr: "{{ item.key.split('.') }}"
_key: "{{ _arr[:-1]|join('.') }}"
_sub: "{{ _arr[-1] }}"
_val: "{{ item.value }}"
下一个选项是编写一个过滤器。例如,使用下面的过滤器并设置另一个 separator
def dict_flatten(d, separator='.'):
out = {}
def flatten(x, name=''):
if type(x) is dict:
for a in x:
flatten(x[a], name + a + separator)
elif type(x) is list:
i = 0
for a in sorted(x):
flatten(a, name + str(i) + separator)
i += 1
else:
out[name[:-1]] = x
flatten(d)
return out
查看源代码。